java 多线程
- 锁(synchronized)
- synchronized 关键字
- wait notify 实现线程通讯
- wait 和 sleep区别
- 自己设计显示锁
自己仅作 java 多线程的记录,看视频主要还是看书看不下去了…
锁(synchronized)
synchronized 关键字
synchronized 可以放在方法上,此时加锁的对象是this,也可以加锁在同步代码块上。
以下实体类,当我们调用的时候,会发现互斥的,证明方法上加的锁是this锁(类对象锁)
如果synchronized 的对象不一致,则不会互斥(即方法调用不会等待)
public class ThreadTestDayTwo {
public synchronized void get1() throws InterruptedException {
System.out.println("123");
Thread.sleep(10000);
}
public synchronized void get2() throws InterruptedException {
System.out.println("456");
Thread.sleep(10000);
}
}
wait notify 实现线程通讯
实现生产者和消费者
生产者和消费者的关系: 生产者 生产一条数据的时候就要等待,而消费者消费一条数据的时候就要通知生产者继续生产
/**
* @Author: shengjm
* @Date: 2020/2/5 19:40
* @Description: 生产者和消费者
*/
public class ProduceCustomerTest {
private final Object object = new Object();
private volatile boolean isCustomer = true;
private int i = 1;
public void produce() {
synchronized (object) {
if (isCustomer) {
System.out.println("p->" + i++);
isCustomer = false;
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
isCustomer = true;
object.notify();
}
}
}
public void customer(){
synchronized (object) {
if (!isCustomer) {
isCustomer = true;
object.notify();
System.out.println("c->" + i);
} else {
try {
isCustomer = false;
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
ProduceCustomerTest test = new ProduceCustomerTest();
new Thread(new Runnable() {
@Override
public void run() {
while(true)
test.produce();
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
while(true)
test.customer();
}
}).start();
}
}
注意:
貌似看上去没什么问题,但是当我们启用多个线程的时候就会发现,还是出现了卡住的现象,而非线程死锁,问题是notify()的时候,只是通知一个线程,所以要改成使用notifyAll()
还有一处需修改,把if判断改成while
, 原因是当我们notifyAll 的时候,条件并不一定符合,放在while中的话,循环判断,知道条件符合才继续往下运行。
wait 和 sleep区别
1,sleep 不会释放锁,而wait 可以
2,wait 方法,要在synchronized 关键字内
自己设计显示锁
实际开发中,当我们使用synchronized 关键字时候,里面执行的代码时没办法控制的。
所以,我们下面自己设计显示LOCK
/**
* @Author: shengjm
* @Date: 2020/2/6 15:53
* @Description: 显示锁设计
*/
public interface Lock {
class TimeoutException extends Exception{
public TimeoutException(String message){
super(message);
}
}
void lock() throws InterruptedException;
void lock(long mills) throws InterruptedException , TimeoutException;
void unlock();
Collection<Thread> getLockThread();
int getBlockSize();
}
/**
* @Author: shengjm
* @Date: 2020/2/6 15:56
* @Description: 实现类
*/
public class BooleanLock implements Lock {
private boolean initValue;
private Thread currentThread;
Collection<Thread> blockThreadCollection = new ArrayList<>();
public BooleanLock() {
this.initValue = false;
}
@Override
public synchronized void lock() throws InterruptedException {
while(initValue){
blockThreadCollection.add(Thread.currentThread());
this.wait();
}
blockThreadCollection.remove(Thread.currentThread());
initValue = true;
this.currentThread = Thread.currentThread();
}
@Override
public synchronized void lock(long mills) throws InterruptedException, TimeoutException {
if (mills <= 0){
this.lock();
}
long hasRemaining = mills;
long endTime = System.currentTimeMillis() + mills;
while(initValue){
if(hasRemaining <= 0){
throw new TimeoutException(Thread.currentThread() + "time out");
}
blockThreadCollection.add(Thread.currentThread());
this.wait(mills);
hasRemaining = endTime - System.currentTimeMillis();
}
initValue = true;
this.currentThread = Thread.currentThread();
}
@Override
public synchronized void unlock() {
if(this.currentThread == Thread.currentThread()){
this.initValue = false;
System.out.println(Thread.currentThread() + "release the monitor...");
this.notifyAll();
}
}
@Override
public Collection<Thread> getLockThread() {
return Collections.unmodifiableCollection(blockThreadCollection);
}
@Override
public int getBlockSize() {
return blockThreadCollection.size();
}
public static void main(String[] args) {
final BooleanLock booleanLock = new BooleanLock();
Stream.of("T1","T2","T3").forEach((name)->{
new Thread(new Runnable() {
@Override
public void run() {
try {
// booleanLock.lock();
booleanLock.lock(5000); // lock 等待时间,当等待时间小于实际 work方法的时间,则抛出超时异常
Optional.of(Thread.currentThread().getName() + "have the lock monitor...").ifPresent(System.out::println);
work();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
booleanLock.unlock();
}
}
}).start();
});
}
// work 方法模拟实际消耗的时间
private static void work() throws InterruptedException {
Optional.of(Thread.currentThread().getName() + "is working ...").ifPresent(System.out::println);
Thread.sleep(10000);
}
}