Contents
多线程基础
有关Java中多线程的基本使用方式,主要是Thread类的使用。
什么是线程
线程的基本操作
守护线程
线程优先级
基本的线程同步操作
什么是线程
线程是进程的基本单元
线程的基本操作

新建线程
//新建线程
Thread thread = new Thread();
//并启动新线程
thread.start();
//错误启动方式
thread.run();
在新线程中运行某些内容
方式一
Thread thread = new Thread() {
@Override
public void run() {
//...
}
}
thread.start();
方式二
class XxThread implements Runnable {
@Override
public void run() {
//...
}
}
Thread thread = new Thread(new XxThread());
thread.start();
线程终止
Thread.stop()不推荐使用。它回会释放所有的monitor,有可能会导致数据的不一致性。

线程中断
public void Thread.interrupt() //中断线程(实例方法)
public boolean Thread.isInterrupted() //线程是否被中断(实例方法)
public static boolean Thread.interrupted() //判断线程是否被中断,并清除当前中断状态(静态方法)
使用线程中断方式停止线程。
//比如原来某个线程中运行的代码是这样的
public void run(){
while(true) {
//...具体业务
}
}
//------------------------------------------
//然后向其中添加判断是否中断的代码
public void run() {
while(true) {
//判断是否被中断
if(Thread.currentThread().isinterrupted()) break;
//...具体业务
}
}
//在某个位置中断该线程
interrupt();
t1.
//------------------------------------------
//如果线程代码中有sleep()类似的代码,sleep允许在睡眠期间被中断,并清中断,需要特别处理一下
//向其中添加判断是否中断的代码
public void run() {
while(true) {
//判断是否被中断
if(Thread.currentThread().isinterrupted()) break;
//...具体业务
try {
sleep(1000);
catch(InterruptedException e) {
} //从睡眠中被中断业务...
//从睡眠中唤醒(抛出中断异常时,会清中断信号),需重新设置中断状态
Thread.currentThread().interrupt();
}//...具体业务
}
}
//在某个位置中断该线程(也可以中断此线程的睡眠状态)
interrupt();
t1.
线程的挂起与继续执行
挂起(suspend), 继续执行(resume), 对应两个同名方法。 官方不建议使用。
正常使用一般是先suspend然后resume。如果出现意外情况,先resume后suspend会永久挂起。


suspend方法不会释放锁!!!
如果先加锁,然后resume,再suspend,则死锁发生。
线程谦让yield
public static native void yield(); //静态方法,会把当前线程剩余cpu时间片释放掉,让所有进程重新竞争cpu。
等待线程结束join
public final void join() throws InterruptedException();
pubilc final synchronized void join(long millis) throws InterruptedException();
等待某个线程结束再做事情。
join的实现,实际上是
while(isAlive()) {
wait(0);
}
Thread.join()文档上有说明。当线程terminated的时候,线程对象的notifyAll方法被调用,唤醒所有等在在此线程上的wait. 因此这里join会被唤醒向下走。 也因此,不建议在线程实例对象上调用wait,notify,notifyAll方法,因为可能会影响到这里。但是其他对象上调用wait,notify,notifyAll是无所谓的。
守护线程
在后台默默完成一些系统工作的服务。主线程退出,守护线程也会随之退出。 垃圾回收线程,jit线程都可以理解为守护线程。
当一个应用内只剩余一个守护线程时,Java虚拟机就会退出。
Thread thread = new Thread();
//线程启动之前就要设置好
thread.setDeamon(true);
thread.start();
eg

线程优先级
多个线程竞争资源的时候,线程优先级会有影响。
eg
public class Main {
public static void main(String[] args) {
Thread high = new HighPriority("high");
Thread low = new LowPriority("low");
high.setPriority(Thread.MAX_PRIORITY);
low.setPriority(Thread.MIN_PRIORITY);
low.start();
high.start();
}
}
class HighPriority extends Thread {
public HighPriority(String name) {
super(name);
}
public static int count = 0;
@Override
public void run() {
while(true) {
synchronized (Main.class) {
count++;
if(count>100000000) {
System.out.println("High Priority is completed.");
break;
}
}
}
}
}
class LowPriority extends Thread {
public LowPriority(String name) {
super(name);
}
public static int count = 0;
@Override
public void run() {
while(true) {
synchronized (Main.class) {
count++;
if(count>100000000) {
System.out.println("Low Priority is completed.");
break;
}
}
}
}
}
基本的线程同步操作
多线程执行过程中如何通信?
线程被挂起,如何被通知?
线程之间有数据竞争,如何来协调竞争?
链接:https://www.nowcoder.com/questionTerminal/26fc16a2a85e49a5bd5fc2b5759dbbc2?
监视器是一种同步机制。
java中提供了这种同步机制的实现
1、Object类中提供的wait notify notifyall方法
2、synchronized关键字隐式锁 或 Lock显示锁
3、每个对象自带一个锁
4、显示锁的Condition条件,用于协作
程序员可以使用显示锁或隐式锁实现互斥,wait notify notifyall condition 实现协作
synchronized
- 指定加锁对象:给指定对象加锁,进入同步代码前活得给定对象的锁
- 直接所用于实例对象方法:相当于给当前实例加锁,进入同步代码前要获取当前实例的锁
- 直接作用于静态方法:相当于给当前类加锁,进入同步代码前要获取当前类的锁。
Ojbect.wait和Object.notify
wait和notify方法配合使用
object.wait使用前, 线程要先获取对象object的监视器,比如synchronized(object);
object.wait时, 线程会释放获取的object的监视器。
object.notify使用前,线程也必须拥有对象object的监视器,比如synchronized(object);
object.notfiy时,会通知其他某个wait在此object上的线程。但是此时object.notify并没有释放object上监视器,只有监视器被释放后(比如synchronized(object){… object.notify()….}代码块整体结束后,wait在oject上的其他线程才会获取到oject上的监视器,继续向下执行。

eg1: 加在对象上的锁(监视器)
public class Main {
//暂不考虑join时被中断的情况
public static void main(String[] args) throws InterruptedException {
//这里可以分别使用不同的实例
// Thread t1 = new Thread(new AccountSync(), "t1");
// Thread t2 = new Thread(new AccountSync(), "t2");
//也可以使用相同实例
AccountSync accountSync = new AccountSync();
Thread t1 = new Thread(accountSync, "t1");
Thread t2 = new Thread(accountSync, "t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(AccountSync.count);
}
}
class AccountSync implements Runnable {
//监视器/监视对象
public static Object lock = new Object();
public static int count = 0;
@Override
public void run() {
for(int i = 0; i < 100000000; i++) {
synchronized (lock) {
count++;
}
}
}
}
eg2:加在类上的锁(监视器)或直接加在静态方法上
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new AccountSync2(), "t1");
Thread t2 = new Thread(new AccountSync2(), "t2");
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(AccountSync2.count);
}
}
class AccountSync2 implements Runnable {
public static int count = 0;
public static synchronized void increase() {
count++;
}
@Override
public void run() {
for(int i = 0; i < 100000000; i++ ) {
increase();
}
}
}
eg3: object.wait与object.notify实例
public class Main {
final static Object object = new Object();
public static class T1 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis() + ": T1 thread started!");
try {
System.out.println("T1 wait for object.");
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + ": T1 thread ended!");
}
}
}
public static class T2 extends Thread {
@Override
public void run() {
synchronized (object) {
System.out.println(System.currentTimeMillis() + ": T2 thread started!");
object.notify();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println(System.currentTimeMillis() + ": T2 thread ended.");
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new T1();
Thread t2 = new T2();
t1.start();
Thread.sleep(1000);
t2.start();
t1.join();
t2.join();
}
}
Java线程状态与线程通讯wait/notify,park/unpark机制:https://blog.csdn.net/qq_38525526/article/details/90180451
习题
使用wait和notify实现一个线程安全的队列
使用 wait notify 实现一个队列,队列有2个方法,add 和 get 。
add方法往队列中添加元素,get方法往队列中获得元素。队列必须是线程安全的。
如果get执行时,队列为空,线程必须阻塞等待,直到有队列有数据。
如果add时,队列已经满,则add线程要等待,直到队列有空闲空间。
import java.util.LinkedList;
import java.util.List;
/**
* 使用 wait notify 实现一个队列,队列有2个方法,add 和 get 。
* add方法往队列中添加元素,get方法往队列中获得元素。队列必须是线程安全的。
* 如果get执行时,队列为空,线程必须阻塞等待,直到有队列有数据。
* 如果add时,队列已经满,则add线程要等待,直到队列有空闲空间。
*
* 参考:https://maimai.cn/article/detail?fid=1684676370&efid=etOPh0qFntMswKABdHTdGg
*
* @param <T> 元素类型
*/
public class SafeQueue<T> {
public static final int MAX_SIZE = 100;
private LinkedList<T> list = new LinkedList<>();
public void add(T ele) {
synchronized (list) {
//这里if不合适,因为这里wait可能是被调用add的线程唤醒的
// if (list.size() >= MAX_SIZE) {
while (list.size() >= MAX_SIZE) {
try {
wait();
list.catch (InterruptedException e) {
} // throw new RuntimeException(e);
}
}System.out.println(Thread.currentThread().getName() + ": before add. And current queue size(): " + list.size());
add(ele);
list.//唤醒某一个监视此对象的线程(这里notify()不合适, 因为可能唤醒的是add中的wait,有可能造成死锁)
// list.notify();
notifyAll();
list.
}
}
public T get() {
null;
T ele = synchronized (list) {
//如果队列为空,需要阻塞等待
//这里if不合适,因为wait可能是被调用get的线程唤醒的
// if (list.size() == 0) {
while (list.size() == 0) {
try {
wait();
list.catch (InterruptedException e) {
} // throw new RuntimeException(e);
}
}System.out.println(Thread.currentThread().getName() + ": before poll. And current queue size(): " + list.size());
poll();
ele = list.//唤醒监视此对象的线程(这里notify()不合适,因为有可能唤醒的是调用get的线程,有可能造成死锁)
// list.notify();
notifyAll();
list.
}return ele;
}
}
发表回复