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());
}
}