线程的生命周期
利用继承的方式创建线程并实现同步
1 package com.vegeta; 2 3 /** 4 * 继承方式创建线程,实现同步 5 * 6 * @author:qxz 7 * @create 2020-04-02 10:45 8 */ 9 public class TestExtends { 10 11 public static void main(String[] args) { 12 Window window1 = new Window(); 13 window1.setName("窗口一"); 14 Window window2 = new Window(); 15 window2.setName("窗口二"); 16 Window window3 = new Window(); 17 window3.setName("窗口三"); 18 window1.start(); 19 window2.start(); 20 window3.start(); 21 } 22 23 } 24 25 class Window extends Thread { 26 private static int ticket = 100; 27 28 @Override 29 public void run() { 30 while (true) { 31 synchronized (Window.class) { 32 if (ticket > 0) { 33 try { 34 Thread.sleep(100); 35 } catch (InterruptedException e) { 36 e.printStackTrace(); 37 } 38 System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "号票"); 39 ticket--; 40 } else { 41 break; 42 } 43 } 44 } 45 } 46 }
利用实现Runnable接口创建多线程并实现同步
1 package com.vegeta; 2 3 /** 4 * 利用实现Runnable接口方式创建多线程并实现同步 5 * 6 * @author:qxz 7 * @create 2020-04-02 11:14 8 */ 9 public class TestRunnable { 10 public static void main(String[] args) { 11 WindowRunnable windowRunnable = new WindowRunnable(); 12 Thread window1 = new Thread(windowRunnable); 13 window1.setName("窗口一"); 14 Thread window2 = new Thread(windowRunnable); 15 window2.setName("窗口二"); 16 Thread window3 = new Thread(windowRunnable); 17 window3.setName("窗口三"); 18 window1.start(); 19 window2.start(); 20 window3.start(); 21 } 22 } 23 24 class WindowRunnable implements Runnable{ 25 private int ticket = 100; 26 27 public void run() { 28 while (true) { 29 synchronized (this) { 30 if (ticket > 0) { 31 try { 32 Thread.sleep(100); 33 } catch (InterruptedException e) { 34 e.printStackTrace(); 35 } 36 System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "号票"); 37 ticket--; 38 } else { 39 break; 40 } 41 } 42 } 43 } 44 }
实现Callable接口创建多线程,Callable接口不适合这种场景,它是带返回值的
1 package com.vegeta; 2 3 import java.util.concurrent.Callable; 4 import java.util.concurrent.ExecutionException; 5 import java.util.concurrent.FutureTask; 6 7 /** 8 * 实现Callable接口能获取返回值 9 * 10 * @author:qxz 11 * @create 2020-04-02 11:32 12 */ 13 public class TestCallable { 14 public static void main(String[] args) throws ExecutionException, InterruptedException { 15 WindowCallable wc = new WindowCallable(); 16 FutureTask<Integer> futureTask1 = new FutureTask(wc); 17 FutureTask<Integer> futureTask2 = new FutureTask(wc); 18 FutureTask<Integer> futureTask3 = new FutureTask(wc); 19 Thread window1 = new Thread(futureTask1); 20 window1.setName("窗口一"); 21 Thread window2 = new Thread(futureTask2); 22 window2.setName("窗口二"); 23 Thread window3 = new Thread(futureTask3); 24 window3.setName("窗口三"); 25 window1.start(); 26 Integer i1 = futureTask1.get(); 27 System.out.println(i1); 28 window2.start(); 29 Integer i2 = futureTask2.get(); 30 System.out.println(i2); 31 window3.start(); 32 Integer i3 = futureTask3.get(); 33 System.out.println(i3); 34 35 System.out.println(i1 + i2 + i3); 36 } 37 } 38 39 class WindowCallable implements Callable<Integer>{ 40 41 public Integer call() throws Exception { 42 return 1 + 2; 43 } 44 }
利用线程池实现同步
1 package com.vegeta; 2 3 import java.util.concurrent.ExecutorService; 4 import java.util.concurrent.Executors; 5 import java.util.concurrent.ThreadPoolExecutor; 6 7 /** 8 * 利用线程池 实现同步 9 * 10 * @author:qxz 11 * @create 2020-04-02 13:29 12 */ 13 public class TestPool { 14 public static void main(String[] args) { 15 ExecutorService executorService = Executors.newFixedThreadPool(10); 16 ThreadPoolExecutor executor = (ThreadPoolExecutor) executorService; 17 WindowPool windowPool = new WindowPool(); 18 executor.execute(windowPool); 19 executor.execute(windowPool); 20 executor.execute(windowPool); 21 executor.shutdown(); 22 } 23 } 24 25 class WindowPool implements Runnable{ 26 private int ticket = 100; 27 28 public void run() { 29 while (true) { 30 synchronized (this) { 31 if (ticket > 0) { 32 try { 33 Thread.sleep(100); 34 } catch (InterruptedException e) { 35 e.printStackTrace(); 36 } 37 System.out.println(Thread.currentThread().getName() + "卖出了第" + ticket + "号票"); 38 ticket--; 39 } else { 40 break; 41 } 42 } 43 } 44 } 45 }
线程交互
1 /** 2 * 线程通信的例子:使用两个线程打印 1-100。线程1, 线程2 交替打印 3 * 4 * 涉及到的三个方法: 5 * wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。 6 * notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。 7 * notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。 8 * 9 * 说明: 10 * 1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。 11 * 2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。 12 * 否则,会出现IllegalMonitorStateException异常 13 * 3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。 14 * 15 * 面试题:sleep() 和 wait()的异同? 16 * 1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。 17 * 2.不同点:1)两个方法声明的位置不同:Thread类中声明sleep() , Object类中声明wait() 18 * 2)调用的要求不同:sleep()可以在任何需要的场景下调用。 wait()必须使用在同步代码块或同步方法中 19 * 3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。 20 * 21 * @author shkstart 22 * @create 2019-02-15 下午 4:21 23 */ 24 public class CommunicationTest { 25 public static void main(String[] args) { 26 Number number = new Number(); 27 Thread t1 = new Thread(number); 28 Thread t2 = new Thread(number); 29 30 t1.setName("线程1"); 31 t2.setName("线程2"); 32 33 t1.start(); 34 t2.start(); 35 } 36 } 37 38 class Number implements Runnable{ 39 private int number = 1; 40 41 public void run() { 42 while(true){ 43 synchronized (this) { 44 this.notify(); 45 if(number <= 100){ 46 try { 47 Thread.sleep(10); 48 } catch (InterruptedException e) { 49 e.printStackTrace(); 50 } 51 System.out.println(Thread.currentThread().getName() + ":" + number); 52 number++; 53 try { 54 //使得调用如下wait()方法的线程进入阻塞状态 55 this.wait(); 56 } catch (InterruptedException e) { 57 e.printStackTrace(); 58 } 59 }else{ 60 break; 61 } 62 } 63 } 64 } 65 }