多线程的创建
继承Thread类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class ThreadDemo extends Thread { private String threadName = null;
ThreadDemo(String threadName) { this.threadName = threadName; }
@Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(threadName + ": " + i); } }
@Override public synchronized void start() { System.out.println("线程:" + threadName + "启动"); super.start(); } }
public class Multithreading { public static void main(String[] args) { ThreadDemo t1 = new Test.ThreadDemo("线程1"); t1.start(); } }
|
实现Runnable接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class RunnableDemo implements Runnable { private String threadName = null;
RunnableDemo(String threadName) { this.threadName = threadName; }
@Override public void run() { for (int i = 0; i < 10; i++) { System.out.println(threadName + ": " + i); } } }
public class Multithreading { public static void main(String[] args) { RunnableDemo r1 = new Test.RunnableDemo("线程1"); Thread t1 = new Thread(r1);
t1.start(); } }
|
实现Callable接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class CallableDemo implements Callable<Integer>{
private int ticket = 100;
@Override public Integer call() throws Exception { while (ticket > 0) { System.out.println(Thread.currentThread().getName() + "获得票 号码为:" + ticket--); } return ticket; } }
public class Multithreading { public static void main(String[] args) { FutureTask<Integer> futureTask = new FutureTask<>(new CallableDemo()); new Thread(futureTask).start();
try { Integer ticket = futureTask.get(); System.out.println("主线程获取的返回值:"+ticket); } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { throw new RuntimeException(e); }
} }
|
线程池
线程池的好处是利于管理线程,在需要的时候调线程,不需要再一个一个创建线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class Multithreading { public static void main(String[] args) { ExecutorService service = Executors.newFixedThreadPool(10); ThreadPoolExecutor service1 = (ThreadPoolExecutor) service;
service1.execute(new RunnableDemo()); Future<Integer> submit = service1.submit(new CallableDemo()); service1.submit(()=>{ ... });
service1.shutdown(); } }
|
多线程的使用(抢票例子)
多个线程取一个票,票的数量是有限的,所以需要多个线程对一个数据进行操作,四种方式都可以实现
Thread方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class ThreadDemo extends Thread{ private static int ticket = 10;
public ThreadDemo(String name) { super(name); }
@Override public void run() { while (ticket > 0){ System.out.println(getName()+"获得票 号码为:"+ticket--); } } }
|
Runnable方式
1 2 3 4 5 6 7 8 9 10
| class RunnableDemo implements Runnable { private int ticket = 10;
@Override public void run() { while (ticket > 0) { System.out.println(Thread.currentThread().getName() + "获得票 号码为:" + ticket--); } } }
|
对比两种方式可以明显的发现,在继承Thread方式来实现多线程的时候我们需要在ticket前加static修饰,如果不修饰票数则修改的数据将不会是同一个数据。
而Runnable方式则不需要static修饰,若要对共同数据进行操作显而易见的Runnable会更加适合,而且在使用中也会更多的使用Runnable来实现多线程。
但是两个方法在线程上不安全的,当两个线程被阻塞后同时获取到数据的时候票数就会重复了。
特别是在println之前加入Thread.sleep(100)
会更明显的观察到不安全的多线程所带来的bug。
线程同步锁
同步锁分为同步方法和同步代码块,还是以获取车票为例
同步代码块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class RunnableDemo implements Runnable { private int ticket = 100;
@Override public void run() { while (true) { synchronized (this) {
if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName() + "获取票 号码为:" + ticket--); } else { break; } } } } }
|
同步方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class RunnableDemo implements Runnable { private int ticket = 100;
@Override public void run() { while (ticket > 0){ show(); } }
public synchronized void show() { if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName() + "获取票 号码为:" + ticket--); } } }
|
ReentrantLock(JDK 5.0+)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class Window3 implements Runnable{ private int ticket = 100; private ReentrantLock lock = new ReentrantLock(true);
@Override public void run() { while (ticket > 0) { try { lock.lock();
if (ticket > 0) { try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); }
System.out.println(Thread.currentThread().getName() + "窗口 票数为:" + ticket--); } } finally { lock.unlock(); } } } }
|
单例模式的安全问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Bank{ private static Bank instance = null;
public static synchronized Bank getInstance(){ synchronized (Bank.class) { if (instance == null){ instance = new Bank(); } return instance; } if (instance == null){ synchronized (Bank.class){ if (instance == null){ instance = new Test.Bank(); } } } return instance; } }
|