目录
多线程
进程和线程
多线程实现
设置获取线程名称
线程调度(设置线程优先级)
多线程实现方式一:继承Thread类,重写run()方法(Thread类实现了Runnable接口)
直接调用run()方法,相当于普通方法的调用,要想启动多个线程,需要使用start()方法,然后由jvm调用run()方法
方法名
说明
void run()
在线程开启后,此方法将被调用执行
void start()
使此线程开始执行,Java虚拟机会调用run方法()
public static void main(String[] args) { ThreadTest t1 = new ThreadTest(); ThreadTest t2 = new ThreadTest(); t1.setName("线程1"); t2.setName("线程2"); /* public final synchronized void setName(String name) { this.checkAccess(); if (name == null) { throw new NullPointerException("name cannot be null"); } else { this.name = name; if (this.threadStatus != 0) { this.setNativeName(name); } } }*/ t1.getName(); /* public final String getName() { return this.name; }*/ t1.start(); t2.start(); //线程名称为 Thread-0 的原因 /* public Thread() { //Thread-0,1,2,3... this((ThreadGroup)null, (Runnable)null, "Thread-" + nextThreadNum(), 0L); } private static int threadInitNumber; private static synchronized int nextThreadNum() { return threadInitNumber++; } */ }获取当前方法所在线程的名称
public static void main(String[] args) { //获取当前方法所在线程的名称 // currentThread() 返回对当前正在执行的线程对象的引用。 //Thread thread = Thread.currentThread(); Thread.currentThread().setName("主线程"); System.out.println(Thread.currentThread().getName()); }注意:优先级高的线程只是获取cpu的时间相对多一些,不是绝对的占有
public static void main(String[] args) { // getPriority() 返回此线程的优先级。线程默认优先级为5 // setPriority(int newPriority) 更改此线程的优先级。 //Thread thread = Thread.currentThread(); System.out.println(Thread.NORM_PRIORITY); //默认优先级5 System.out.println(Thread.MIN_PRIORITY); //最低优先级1 System.out.println(Thread.MAX_PRIORITY); //最高优先级10 ThreadTest t1 = new ThreadTest(); ThreadTest t2 = new ThreadTest(); ThreadTest t3 = new ThreadTest(); //设置线程名称 t1.setName("飞机"); t2.setName("和谐号"); t3.setName("汽车"); //设置优先级 注意:优先级高的线程只是获取cpu的时间相对多一些,不是绝对的占有 t1.setPriority(10); t2.setPriority(5); t3.setPriority(1); t1.start(); t2.start(); t3.start(); } /* 飞机--0 ... 飞机--16 飞机--17 和谐号--0 飞机--18 飞机--19 飞机--20 飞机--21 飞机--22 和谐号--1 飞机--23 和谐号--2 飞机--24 和谐号--3 飞机--25 飞机--26 和谐号--4 ... 汽车--98 汽车--99 */注意:优先级高的线程只是获取cpu的时间相对多一些,不是绝对的占有,所以和谐号线程会出在飞机线程执行过程中也执行
方法名
说明
static void sleep(long millis)
使当前正在执行的线程停留(暂停执行)指定的毫秒数
void join()
等待这个线程死亡
void setDaemon(boolean on)
将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
public static void main(String[] args) { ThreadTest t1 = new ThreadTest(); ThreadTest t2 = new ThreadTest(); ThreadTest t3 = new ThreadTest(); //设置线程名称 t1.setName("李淳风"); t2.setName("袁天罡"); t3.setName("李茂贞"); t1.start(); try { //等待此线程执行完成之后其它线程才能开始执行 //位置只能放置t1.start()之后,且不能在其它的线程start之后 t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } t2.start(); t3.start(); } public class ThreadTest extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(this.getName() + "--" + i); /*try { //使当前正在执行的线程停留(暂停执行)指定的毫秒数 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }*/ } } } public static void main(String[] args) { ThreadTest t1 = new ThreadTest(); ThreadTest t2 = new ThreadTest(); Thread mainThread = Thread.currentThread(); mainThread.setName("李唐"); //设置线程名称 t1.setName("李淳风"); t2.setName("袁天罡"); //设置t1、t2为守护进程 //将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出 //当主线程退出后守护进程立刻也会退出 t1.setDaemon(true); t2.setDaemon(true); t1.start(); t2.start(); for (int i = 0; i < 10; i++) { System.out.println(mainThread.getName() + "--" + i); } } public class ThreadTest extends Thread { @Override public void run() { for (int i = 0; i < 100; i++) { System.out.println(this.getName() + "--" + i); /*try { //使当前正在执行的线程停留(暂停执行)指定的毫秒数 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }*/ } } } /* 李淳风--0 李淳风--1 李淳风--2 李淳风--3 李淳风--4 李淳风--5 李淳风--6 李淳风--7 李淳风--8 李淳风--9 李淳风--10 李淳风--11 李淳风--12 袁天罡--0 李淳风--13 袁天罡--1 李淳风--14 袁天罡--2 李唐--0 李淳风--15 李唐--1 袁天罡--3 李唐--2 李唐--3 李唐--4 李唐--5 李淳风--16 李淳风--17 李唐--6 李唐--7 李唐--8 李唐--9 袁天罡--4 袁天罡--5 袁天罡--6 袁天罡--7 袁天罡--8 袁天罡--9 Process finished with exit code 0 */多线程实现方式二:直接实现Runnable接口,重写run()方法
方法名
说明
Thread(Runnable target)
分配一个新的Thread对象
Thread(Runnable target, String name)
分配一个新的Thread对象
所以推荐使用直接实现Runnable接口的方式实现多线程
public static void main(String[] args) { RunnableTest runnableTest = new RunnableTest(); /*//创建Thread对象,将Runnable实现类的对象作为构造方法的参数,Thread(Runnable target) 分配一个新的 Thread对象。 Thread thread1 = new Thread(runnableTest); Thread thread2 = new Thread(runnableTest); Thread thread3 = new Thread(runnableTest);*/ //创建Thread对象,将Runnable实现类的对象和线程名称作为构造方法的参数,Thread(Runnable target, String name) 分配一个新的 Thread对象。 Thread thread1 = new Thread(runnableTest, "线程1"); Thread thread2 = new Thread(runnableTest, "线程2"); Thread thread3 = new Thread(runnableTest, "线程3"); thread1.start(); thread2.start(); thread3.start(); } public class RunnableTest implements Runnable { @Override public void run() { for(int i=0;i<100;i++){ System.out.println(Thread.currentThread().getName() + "--" + i); } } } public class SellTicket implements Runnable{ private int ticketNum = 100; @Override public void run() { boolean flag = true; while(flag){ if (ticketNum>0){ try { //模拟出票时间100毫秒 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + ticketNum + "张票"); ticketNum--; }else{ System.out.println(Thread.currentThread().getName() + "票已售完"); flag = false; } } } } public static void main(String[] args) { SellTicket sellTicket = new SellTicket(); Thread thread1 = new Thread(sellTicket, "窗口1"); Thread thread2 = new Thread(sellTicket, "窗口2"); Thread thread3 = new Thread(sellTicket, "窗口3"); thread1.start(); thread2.start(); thread3.start(); }注意:synchronized的锁可以是任意一个对象,但是如果要让其生效只能使用同一把锁。
synchronized(任意对象) { 共享数据代码块 } public class SellTicket implements Runnable{ private int ticketNum = 100; private Object lock = new Object(); //多线程线程安全问题需要同一把锁才能解决问题 @Override public void run() { boolean flag = true; while(flag){ synchronized(lock) { if (ticketNum > 0) { try { //模拟出票时间100毫秒 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + ticketNum + "张票"); ticketNum--; } else { System.out.println(Thread.currentThread().getName() + "票已售完"); flag = false; } } } } } public static void main(String[] args) { SellTicket sellTicket = new SellTicket(); Thread thread1 = new Thread(sellTicket, "窗口1"); Thread thread2 = new Thread(sellTicket, "窗口2"); Thread thread3 = new Thread(sellTicket, "窗口3"); thread1.start(); thread2.start(); thread3.start(); } /* 窗口2正在出售第100张票 窗口1正在出售第99张票 ... 窗口3正在出售第2张票 窗口1正在出售第1张票 窗口1票已售完 窗口2票已售完 窗口3票已售完 Process finished with exit code 0 */普通同步方法格式:
public synchronized void methodName() { 代码块 }普通同步方法格式:
public static synchronized void methodName() { 代码块 }public class SellTicket implements Runnable { private static int ticketNum = 100; private Object lock = new Object(); //多线程线程安全问题需要同一把锁才能解决问题 private int num = 0; @Override public void run() { boolean flag = true; while (flag) { if (num % 2 == 0) { //synchronized(lock) { //普通锁为任意对象 //synchronized (this) { //普通方法同步锁为当前类当前对象 synchronized (SellTicket.class) { //静态方法同步锁为当前类 if (ticketNum > 0) { try { //模拟出票时间100毫秒 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + ticketNum + "张票"); ticketNum--; } else { System.out.println(Thread.currentThread().getName() + "票已售完"); flag = false; } } } else { flag = sellTicket(flag); } num++; } } public synchronized boolean sellTicket(boolean flag) { if (ticketNum > 0) { try { //模拟出票时间100毫秒 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + ticketNum + "张票"); ticketNum--; } else { System.out.println(Thread.currentThread().getName() + "票已售完"); flag = false; } return flag; } public static synchronized boolean sellTicketStatic(boolean flag) { if (ticketNum > 0) { try { //模拟出票时间100毫秒 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + ticketNum + "张票"); ticketNum--; } else { System.out.println(Thread.currentThread().getName() + "票已售完"); flag = false; } return flag; } } public static void main(String[] args) { SellTicket sellTicket = new SellTicket(); Thread thread1 = new Thread(sellTicket, "窗口1"); Thread thread2 = new Thread(sellTicket, "窗口2"); Thread thread3 = new Thread(sellTicket, "窗口3"); thread1.start(); thread2.start(); thread3.start(); }
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
ReentrantLock构造方法
方法名
说明
ReentrantLock()
创建一个ReentrantLock的实例
加锁解锁方法
方法名
说明
void lock()
获得锁
void unlock()
释放锁
public class SellTicket implements Runnable { private static int ticketNum = 100; private Lock lock = new ReentrantLock(); @Override public void run() { boolean flag = true; while (flag) { try { lock.lock(); if (ticketNum > 0) { try { //模拟出票时间100毫秒 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在出售第" + ticketNum + "张票"); ticketNum--; } else { System.out.println(Thread.currentThread().getName() + "票已售完"); flag = false; } } finally { lock.unlock(); } } } } public static void main(String[] args) { SellTicket sellTicket = new SellTicket(); Thread thread1 = new Thread(sellTicket, "窗口1"); Thread thread2 = new Thread(sellTicket, "窗口2"); Thread thread3 = new Thread(sellTicket, "窗口3"); thread1.start(); thread2.start(); thread3.start(); }生产者和消费者模式概述
方法名
说明
void wait()
导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法
void notify()
唤醒正在等待对象监视器的单个线程
void notifyAll()
唤醒正在等待对象监视器的所有线程
public class Bok { //定义一个成员变量,表示第x瓶奶 private int milkNum; //定义一个成员变量,表示奶箱的状态 private boolean status = false; public synchronized void putMilk(int milkNum){ if (status){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.milkNum = milkNum; System.out.println("生产者生产第: " + this.milkNum + "牛奶"); //生产完毕之后,修改奶箱状态 this.status = true; //唤醒其他等待的线程 notifyAll(); } public synchronized void getMilk(){ if (!status){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.milkNum = milkNum; System.out.println("消费者消费第: " + this.milkNum + "牛奶"); //消费完毕之后,修改奶箱状态 this.status = false; //唤醒其他等待的线程 notifyAll(); } } public class Producer implements Runnable{ private Bok b; public Producer() { } public Producer(Bok b) { this.b = b; } @Override public void run() { for(int i=0;i<10;i++){ b.putMilk(i); } System.out.println("牛奶以生产完成!"); } } public class Custumer implements Runnable{ private Bok b; public Custumer() { } public Custumer(Bok b) { this.b = b; } @Override public void run(){ boolean flag = true; while(flag){ b.getMilk(); } } } public static void main(String[] args) { //创建奶箱对象,这是共享数据区域 Bok b = new Bok(); //创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 Producer prod = new Producer(b); //创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作 Custumer cust = new Custumer(b); //创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递 Thread producer = new Thread(prod); Thread custumer = new Thread(cust); //启动线程 producer.start(); custumer.start(); } /* 生产者生产第: 0牛奶 消费者消费第: 0牛奶 生产者生产第: 1牛奶 消费者消费第: 1牛奶 生产者生产第: 2牛奶 消费者消费第: 2牛奶 生产者生产第: 3牛奶 消费者消费第: 3牛奶 生产者生产第: 4牛奶 消费者消费第: 4牛奶 生产者生产第: 5牛奶 消费者消费第: 5牛奶 生产者生产第: 6牛奶 消费者消费第: 6牛奶 生产者生产第: 7牛奶 消费者消费第: 7牛奶 生产者生产第: 8牛奶 消费者消费第: 8牛奶 生产者生产第: 9牛奶 消费者消费第: 9牛奶 牛奶以生产完成! */