Java多线程基础
等待和唤醒
wait()
线程等待,等待的过程中,释放锁,需要其他线程调用notify去唤醒
notify()
唤醒一个等待的线程,如果有多个线程等待,则随机一条唤醒
notifyAll()
唤醒所有等待的线程
Lock锁
是一个接口
使用
获取 其 实现类 ReentrantLock
方法
lock()
获取锁
unlock()
释放锁
synchronized 与lock的区别
synchronized:不管是同步代码块还是同步方法,都需要在结束一对{}之后,释放锁对象
Lock:是通过两个方法控制需要被同步的代码,更灵活(两个方法为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 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class MyTicket implements Runnable { int ticket = 100; Lock lock = new ReentrantLock(); @Override public void run() { while (true) { try { Thread.sleep(100L); lock.lock(); if (ticket > 0) { System.out.println(Thread.currentThread().getName() + \"买了第\" + ticket + \"张票\"); ticket--; } } catch (InterruptedException e) { throw new RuntimeException(e); }finally { lock.unlock(); } } } }
public class Test01 { public static void main(String[] args) { MyTicket myTicket = new MyTicket(); Thread t1 = new Thread(myTicket, "张三"); Thread t2 = new Thread(myTicket, "李四"); Thread t3 = new Thread(myTicket, "王五"); t1.start(); t2.start(); t3.start();
}
}
|
Callable
接口,实现多线程的一种方式
Callable是一个接口,类似于Runnable
方法
1.V call()
设置线程任务,类似于run()
方法,与之不同的是call可以throw异常,并且还有返回值
2.call方法和run方法的区别:
a.相同点:都是设置线程任务的
b.不同点:
(1)call方法有返回值,而且有异常可以throws
(2)run方法没有返回值,而且有异常不可以throws
3.内容
a.是一个泛型接口。
b.泛型:用于指定我们操作什么类型的数据,<>中只能写引用数据类型,如果泛型不写,默认是Object类型数据。
c.实现Callable接口时,指定泛型是什么类型的,重写的call方法返回值就是什么类型的。
4.获取call方法返回值: FutureTask<V>
a. FutureTask<V>
实现了一个接口: Future <V>
b. FutureTask<V>
中有一个方法:
5.V get()
-> 获取call方法的返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class MyCallable implements Callable<String> { @Override public String call() throws Exception { return "ssssss"; } } public class Test { public static void main(String[] args) throws ExecutionException, InterruptedException { MyCallable myCallable = new MyCallable(); FutureTask<String> futureTask = new FutureTask<>(myCallable); Thread t1 = new Thread(futureTask); t1.start(); System.out.println(futureTask.get()); } }
|
线程池
容器中有多条线程对象,来了线程任务,直接线程池中获取线程对象,用完还回去。
获取
1
| static ExecutorService newFixedThreadPool(int nThreads)
|
执行线程任务
Futhre<?> submit(Runnable task)
提交一个Runnable任务用于执行
Future<T> submit(Callable<T> task)
提交一个Callable任务用于执行
返回值接口Futher
用于接收run方法或者call方法返回值的,但是run方法没有返回值,所以可以不用Future接收,执行call方法需要用Future接收
Future中有一个方法:V get() 用于获取call方法返回值
关闭
ExecutorService中的方法:
\nvoid shutdown() 启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务
练习
需求:创建两个线程任务,一个线程任务完成1-100的和,一个线程任务返回一个字符串
1 2 3 4 5 6
| public class MyString implements Callable<String> { @Override public String call() throws Exception { return Thread.currentThread().getName(); } }
|
1 2 3 4 5 6 7 8 9 10
| public class MySum implements Callable<Integer> { @Override public Integer call() throws Exception { int sum = 0; for (int i = 1; i <= 100; i++) { sum+=i; } return sum; } }
|
1 2 3 4 5 6 7 8 9 10
| public class Test01 { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService es = Executors.newFixedThreadPool(2); Future<String> f1 = es.submit(new MyString()); Future<Integer> f2 = es.submit(new MySum()); System.out.println(f1.get()); System.out.println(f2.get()); } }
|