等待和唤醒
wait()
线程等待,等待的过程中,释放锁,需要其他线程调用notify去唤醒
notify()
唤醒一个等待的线程,如果有多个线程等待,则随机一条唤醒
notifyAll()
唤醒所有等待的线程
Lock锁
是一个接口
使用
获取 其 实现类 ReentrantLock
方法
lock()
获取锁
unlock()
释放锁
synchronized 与lock的区别
synchronized:不管是同步代码块还是同步方法,都需要在结束一对{}之后,释放锁对象
Lock:是通过两个方法控制需要被同步的代码,更灵活(两个方法为lock和unlock)
public class MyTicket implements Runnable {
//定义100张票
int ticket = 100;
//创建Lock对象
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
方法
V call()
设置线程任务,类似于run()
方法,与之不同的是call可以throw异常,并且还有返回值
call方法和run方法的区别:
a.相同点:都是设置线程任务的
b.不同点:
call方法有返回值,而且有异常可以throws
run方法没有返回值,而且有异常不可以throws
4.
a.叫做泛型
b.泛型:用于指定我们操作什么类型的数据,<>中只能写引用数据类型,如果泛型不写,默认是Object类型数据
c.实现Callable接口时,指定泛型是什么类型的,重写的call方法返回值就是什么类型的
5.获取call方法返回值: FutureTask<V>
a. FutureTask<V>
实现了一个接口: Future <V>
b. FutureTask<V>
中有一个方法:
V get()
-> 获取call方法的返回值
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(Callable<V> callable)
*/
FutureTask<String> futureTask = new FutureTask<>(myCallable);
//创建Thread对象-> Thread(Runnable target)
Thread t1 = new Thread(futureTask);
t1.start();
//调用get方法获取call方法返回值
System.out.println(futureTask.get());
}
}
线程池
容器中有多条线程对象,来了线程任务,直接线程池中获取线程对象,用完还回去。
获取
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中的方法:
void shutdown() 启动有序关闭,其中先前提交的任务将被执行,但不会接受任何新任务
练习
需求:创建两个线程任务,一个线程任务完成1-100的和,一个线程任务返回一个字符串
public class MyString implements Callable<String> {
@Override
public String call() throws Exception {
return Thread.currentThread().getName();
}
}
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;
}
}
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());
}
}
学习笔记:视频来源尚硅谷