一、Demo1
1、demo1
package com.hskw.demo1;
/**
* synchronized关键字
* synchronized关键字锁定的是对象不是代码块,demo中锁的是object对象的实例
* 锁定的对象有两种:1.类的实例 2.类对象(类锁)
* 加synchronized关键字之后不一定能实现线程安全,具体还要看锁定的对象是否唯一。
*/
public class Demo1 {
private int count = 10;
private Object object = new Object();
public void test(){
synchronized (object){
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
}
}
2、demo2
package com.hskw.demo1;
public class Demo2 {
private int count = 10;
public void test(){
//synchronized(this)锁定的是当前类的实例,这里锁定的是Demo2类的实例
synchronized (this){
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
}
}
3、demo3
package com.hskw.demo1;
public class Demo3 {
private int count = 10;
//直接加在方法声明上,相当于是synchronized(this)
public synchronized void test(){
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
}
4、demo4
package com.hskw.demo1;
public class Demo4 {
private static int count = 10;
//synchronize关键字修饰静态方法锁定的是类对象
//静态方法中synchronize锁定代码块,锁定的对象不能是类的实例,只能是类的.class文件。
public synchronized static void test(){
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
public static void test2(){
synchronized (Demo4.class){//这里不能替换成this
count--;
}
}
}
二、Demo2
1、demo1
package com.hskw.demo2;
import java.util.concurrent.TimeUnit;
/**
* 锁对象的改变
* 锁定某对象o,如果o的属性发生改变,不影响锁的使用
* 但是如果o变成另外一个对象,则锁定的对象发生改变
* 应该避免将锁定对象的引用变成另外一个对象
*/
public class Demo1 {
Object o = new Object();
public void test(){
synchronized (o) {
while (true) {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}
}
}
public static void main(String[] args) {
Demo1 demo = new Demo1();
new Thread(demo :: test, "t1").start();
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread t2 = new Thread(demo :: test, "t2");
demo.o = new Object();
//t2能否执行?
t2.start();
}
}
2、demo2
package com.hskw.demo2;
import java.util.concurrent.TimeUnit;
/**
* 不要以字符串常量作为锁定的对象
* 在下面,test1和test2其实锁定的是同一个对象
*/
public class Demo2 {
String s1 = "hello";
String s2 = "hello";
public void test1(){
synchronized (s1) {
System.out.println("t1 start...");
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t1 end...");
}
}
public void test2(){
synchronized (s2) {
System.out.println("t2 start...");
}
}
public static void main(String[] args) {
Demo2 demo = new Demo2();
new Thread(demo :: test1,"test1").start();
new Thread(demo :: test2,"test2").start();
}
}
3、demo3
package com.hskw.demo2;
import java.util.concurrent.TimeUnit;
/**
* 同步代码快中的语句越少越好
* 比较test1和test2
* 业务逻辑中只有count++这句需要sync,这时不应该给整个方法上锁
* 采用细粒度的锁,可以使线程争用时间变短,从而提高效率
*/
public class Demo3 {
int count = 0;
public synchronized void test1(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
count ++;
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void test2(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (this) {
count ++;
}
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
三、Demo3
1、demo1
package com.hskw.demo3;
/**
* 问题就在于线程重入的问题,
* 第一个线程减了个1变成9了,还没打印,第二个线程又减了个1,第三个线程又减了个1,
* 这时候虽然第一个线程只减了一个1但是却打印出来一个7(这里情况是不一定的)
* 可以给方法加上synchronized
*/
public class Demo1 implements Runnable{
private int count = 10;
@Override
public /*synchronized*/ void run() {
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
public static void main(String[] args) {
Demo1 demo = new Demo1();
for (int i = 0; i < 5; i++) {
new Thread(demo,"THREAD" + i).start();
}
}
}
2、demo2
package com.hskw.demo3;
public class Demo2 implements Runnable{
private int count = 10;
@Override
public synchronized void run() {
count--;
System.out.println(Thread.currentThread().getName() + " count = " + count);
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
//相比较Demo1,这里是new了五个对象,每个线程对应都拿到各自的锁标记,可以同时执行。
Demo2 demo = new Demo2();
new Thread(demo,"THREAD" + i).start();
}
}
}
四、Demo4
package com.hskw.demo4;
//同步方法和非同步方法是否可以同时调用?可以
public class Demo{
public synchronized void test1(){
System.out.println(Thread.currentThread().getName() + " test1 start...");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " test1 end...");
}
public void test2(){
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " test2");
}
public static void main(String[] args) {
Demo demo = new Demo();
new Thread(demo :: test1,"test1").start();
new Thread(demo :: test2,"test2").start();
}
}
五、Demo5
package com.hskw.demo5;
import java.util.concurrent.TimeUnit;
/**
* 脏读问题
* 实际业务当中应该看是否允许脏读,不允许的情况下对读方法也要加锁
*/
public class Demo {
String name;
double balance;
public synchronized void set(String name,double balance){
this.name = name;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.balance = balance;
}
public /*synchronized*/ double getBalance(String name){
return this.balance;
}
public static void main(String[] args) {
Demo demo = new Demo();
new Thread(()->demo.set("huaan",100.0)).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(demo.getBalance("huaan"));//
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(demo.getBalance("huaan"));
}
}
六、Demo6
package com.hskw.demo6;
import java.util.concurrent.TimeUnit;
//一个同步方法调用另外一个同步方法,能否得到锁?可以,synchronized本身可支持重入
public class Demo {
synchronized void test1(){
System.out.println("test1 start.........");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
test2();
}
synchronized void test2(){
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("test2 start.......");
}
public static void main(String[] args) {
Demo demo= new Demo();
demo.test1();
}
}
七、Demo7
package com.hskw.demo7;
import java.util.concurrent.TimeUnit;
//这里是重入锁的另外一种情况,继承
public class Demo {
synchronized void test(){
System.out.println("demo test start........");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("demo test end........");
}
public static void main(String[] args) {
new Demo2().test();
}
}
class Demo2 extends Demo {
@Override
synchronized void test(){
System.out.println("demo2 test start........");
super.test();
System.out.println("demo2 test end........");
}
}
八、Demo8
package com.hskw.demo8;
import java.util.concurrent.TimeUnit;
/**
* T2线程能否执行?
*/
public class Demo {
int count = 0;
synchronized void test(){
System.out.println(Thread.currentThread().getName() + " start......");
while (true) {
count ++;
System.out.println(Thread.currentThread().getName() + " count = " + count);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (count == 5) {
//碰到异常的情况,如果没有处理,会自动释放锁,所以T2可以执行。
int i = 1/0;
}
}
}
public static void main(String[] args) {
Demo demo11 = new Demo();
Runnable r = () -> demo11.test();
new Thread(r, "t1").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(r, "t2").start();
}
}
九、Demo9
package com.hskw.demo9;
/**
* volatile 关键字,使一个变量在多个线程间可见
* mian,t1线程都用到一个变量,java默认是T1线程中保留一份副本,这样如果main线程修改了该变量,
* t1线程未必知道
*
* 使用volatile关键字,会让所有线程都会读到变量的修改值
*
* 在下面的代码中,running是存在于堆内存的t对象中
* 当线程t1开始运行的时候,会把running值从内存中读到t1线程的工作区,在运行过程中直接使用这个副本,
* 并不会每次都去读取堆内存,这样,当主线程修改running的值之后,t1线程感知不到,所以不会停止运行
*
* 关于这个例子 在后面会专门花时间再讲
*/
public class Demo {
boolean running = true;
public void test(){
System.out.println("test start...");
while (running){
}
System.out.println("test end...");
}
public static void main(String[] args) {
Demo demo = new Demo();
new Thread(demo :: test,"t1").start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
demo.running = false;
}
}
十、Demo10
package com.hskw.demo10;
import java.util.ArrayList;
import java.util.List;
/**
* 比如说第一个线程加到100了,还没往上加,另外一个线程来了,把100拿过来执行方法,
* 然后第一个线程继续加到101,第二个线程也加到101,他两往回写都是101,线程不会管你加到哪儿了,
* 虽然说加了2但是实际上只加了1.
* volatile并不能保证多个线程共同修改running变量时所带来的不一致问题,
* 也就是说volatile不能替代synchronized或者说volatile保证不了原子性
*/
public class Demo {
volatile int count = 0;
public void test(){
for (int i = 0; i < 10000; i++) {
count ++;
}
}
public static void main(String[] args) {
Demo demo = new Demo();
List<Thread> threads = new ArrayList();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(demo::test, "thread-" + i));
}
threads.forEach((o)->o.start());
threads.forEach((o)->{
try {
o.join();
} catch (Exception e) {
e.printStackTrace();
}
});
System.out.println(demo.count);
}
}
十一、Demo11
package com.hskw.demo11;
import java.util.ArrayList;
import java.util.List;
public class Demo {
int count = 0;
//相比较上一个例子,synchronized既保证了原子性又保证了可见性
public synchronized void test(){
for (int i = 0; i < 10000; i++) {
count ++;
}
}
public static void main(String[] args) {
Demo demo = new Demo();
List<Thread> threads = new ArrayList<Thread>();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(demo::test, "thread-" + i));
}
threads.forEach((o)->o.start());
threads.forEach((o)->{
try {
o.join();
} catch (Exception e) {
e.printStackTrace();
}
});
System.out.println(demo.count);
}
}
十二、Demo12
package com.hskw.demo12;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* atomicXXX
* 一道面试题:多个atomic类连续调用能否构成原子性?
*/
public class Demo {
AtomicInteger count = new AtomicInteger(0);
//比如count加到999了,这时候一个线程拿到count判断,虽然.get方法保证原子性,但是他阻止
//不了其它线程也来判断,所以第一个线程还没加完,第二个线程也进来了,这时候两个线程都给count加了
public void test(){
for (int i = 0; i < 10000; i++) {
if(count.get() < 1000){
count.incrementAndGet();
}
}
}
public static void main(String[] args) {
Demo demo = new Demo();
List<Thread> threads = new ArrayList();
for (int i = 0; i < 10; i++) {
threads.add(new Thread(demo::test, "thread-" + i));
}
threads.forEach((o)->o.start());
threads.forEach((o)->{
try {
o.join();
} catch (Exception e) {
e.printStackTrace();
}
});
System.out.println(demo.count);
}
}
十三、Demo13
1、Container1
package com.hskw.demo13;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 一道面试题:实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,
* 当个数到5个时,线程2给出提示并结束线程2
*
* 这里list在两个线程之间不保证可见性,所以线程2始终结束不了
*/
public class Container1 {
List lists = new ArrayList();
public void add(Object o){
lists.add(o);
}
public int size(){
return lists.size();
}
public static void main(String[] args) {
Container1 c = new Container1();
new Thread(()->{
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}," t1").start();
new Thread(()->{
while (true) {
if (c.size() == 5) {
break;
}
}
System.out.println("t2线程结束");
}, "t2").start();
}
}
2、Container2
package com.hskw.demo13;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 一道面试题:实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,
* 当个数到5个时,线程2给出提示并结束
*
* 有两个问题,第一由于没有加同步,可能size等于5的时候,有另外一个线程加了一下才break,不是很精确
* 第二个问题就是浪费cpu,T2线程用的是死循环
*/
public class Container2 {
volatile List lists = new ArrayList();
public void add(Object o){
lists.add(o);
}
public int size(){
return lists.size();
}
public static void main(String[] args) {
Container2 c = new Container2();
new Thread(()->{
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add " + i);
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}," t1").start();
new Thread(()->{
while (true) {
if (c.size() == 5) {
break;
}
}
System.out.println("t2线程结束");
}, "t2").start();
}
}
3、Container3
package com.hskw.demo13;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 一道面试题:实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,当个数到5个时,
* 线程2给出提示并结束
*
* 这里虽然T2能够及时收到消息唤醒,但是wait会释放锁,notify不会释放锁,所以T1线程结束后
* T2线程才执行完成
*/
public class Container3 {
volatile List lists = new ArrayList();
public void add(Object o){
lists.add(o);
}
public int size(){
return lists.size();
}
public static void main(String[] args) {
Container3 c = new Container3();
Object lock = new Object();
new Thread(()->{
synchronized (lock) {
System.out.println("t2启动");
if (c.size() != 5) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("t2结束");
}
}," t2").start();
new Thread(()->{
System.out.println("t1启动");
synchronized (lock) {
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add " + i);
if (c.size() == 5) {
lock.notify();//唤醒了线程但是不会释放锁
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "t1").start();
}
}
4、Container4
package com.hskw.demo13;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* 一道面试题:实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,
* 当个数到5个时,线程2给出提示并结束
*
* 相比较上一个例子,这里T1里面用wait释放锁,T2能够及时结束
*/
public class Container4 {
volatile List lists = new ArrayList();
public void add(Object o){
lists.add(o);
}
public int size(){
return lists.size();
}
public static void main(String[] args) {
Container4 c = new Container4();
Object lock = new Object();
new Thread(()->{
synchronized (lock) {
System.out.println("t2启动");
if (c.size() != 5) {
try {
lock.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("t2结束");
lock.notify();
}
}," t2").start();
new Thread(()->{
System.out.println("t1启动");
synchronized (lock) {
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add " + i);
if (c.size() == 5) {
lock.notify();
try {
lock.wait();//要释放锁,T2才能得到锁得以执行
} catch (Exception e) {
e.printStackTrace();
}
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}, "t1").start();
}
}
5、Container5
package com.hskw.demo13;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* 一道面试题:实现一个容器,提供两个方法,add,size
* 写两个线程,线程1添加10个元素到容器中,线程2实现监控元素的个数,
* 当个数到5个时,线程2给出提示并结束
*
* CountDownLatch
* 使用await和countdown方法替代wait和notify
* CountDownLatch不涉及锁定,当count的值为零时当前线程继续运行
* 相当于是发令枪,运动员线程调用await等待,计数到0开始运行
* 当不涉及同步,只是涉及线程通信的时候,用synchronized加wait,notify就显得太重了
*/
public class Container5 {
volatile List lists = new ArrayList();
public void add(Object o){
lists.add(o);
}
public int size(){
return lists.size();
}
public static void main(String[] args) {
Container5 c = new Container5();
CountDownLatch latch = new CountDownLatch(1);
new Thread(()->{
System.out.println("t2启动");
if (c.size() != 5) {
System.out.println(c.size()+"==============");
try {
latch.await();//准备
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("t2结束");
}
}," t2").start();
new Thread(()->{
System.out.println("t1启动");
for (int i = 0; i < 10; i++) {
c.add(new Object());
System.out.println("add " + i);
if (c.size() == 5) {
latch.countDown();
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (Exception e) {
e.printStackTrace();
}
}
}, "t1").start();
}
}
十四、Demo14
1、Container1
package com.hskw.demo14;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
/**
* 面试题:写一个固定容量同步容器,拥有Put和get方法,以及getCount方法,
* 能够支持两个生产者线程以及10个消费者线程的阻塞调用
* wait notifyAll
*
* 这里探究为什么大多数情况下wait和while是一起使用的,
* 因为这里是有两个生产者线程并且容器容量是固定的,生产方法加了锁。
* 如果容器满了,这时候第一个生产者线程拿到了锁,他会判断有没有满,如果满了就等待,在等待
* 的时候会释放掉锁资源,这时候第二个生产者线程就会拿到锁,然后他也会判断是否满,因为容器是
* 满了,第二个生产者线程也会等待并且释放锁,当消费者消费之后唤醒所有线程,这时候两个生产者线程
* 都醒来了,因为要竞争锁资源,比如第一个生产者线程拿到了锁,他给容器又加到十了,陷入等待状态,
* 锁资源释放掉,第二个生产者线程这时候拿到锁资源,他会继续执行(从上次睡眠的地方继续),如果是if
* 的话,他在wait阻塞之前就已经执行了一次if,所以不会再执行,而是继续往下执行,那这时候就超过了
* 容器的容量。所以为了让他再一次判断,这里使用while
*/
public class Container1<T>{
private final LinkedList<T> lists = new LinkedList<>();
private final int MAX = 10;
private int count = 0;
public synchronized void put(T t){
while (lists.size() == MAX) {//
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lists.add(t);
++count;
this.notifyAll();
}
public synchronized T get(){
T t = null;
while (lists.size() == 0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t = lists.removeFirst();
count--;
this.notifyAll();
return t;
}
public static void main(String[] args) {
Container1<String> c = new Container1<>();
for (int i = 0; i < 100; i++) {
new Thread(()->{
for (int j = 0; j < 5; j++) {
System.out.println(c.get());
}
}, "c" + i).start();
}
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 2; i++) {
new Thread(()->{
for (int j = 0; j < 25; j++) {
c.put(Thread.currentThread().getName() + "" + j);
}
}, "p" + i).start();
}
}
}
2、Container2
package com.hskw.demo14;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
*
* 使用Lock和Condition来实现
* condition就是在什么条件下怎么做
* 对比上一个例子,Condition的方式可以更加精确的指定哪些线程被唤醒
*
*/
public class Container2<T> {
private final LinkedList<T> lists = new LinkedList<>();
private final int MAX = 10;
private int count = 0;
private Lock lock = new ReentrantLock();
private Condition producer = lock.newCondition();
private Condition consumer = lock.newCondition();
public void put(T t){
try {
lock.lock();
while (lists.size() == MAX) {
producer.await();
}
lists.add(t);
++count;
consumer.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public T get(){
T t = null;
try {
lock.lock();
while (lists.size() == 0) {
consumer.await();
}
t = lists.removeFirst();
count --;
producer.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
return t;
}
public static void main(String[] args) {
Container2<String> c = new Container2<>();
for (int i = 0; i < 100; i++) {
new Thread(()->{
for (int j = 0; j < 5; j++) {
System.out.println(c.get());
}
}, "c" + i).start();
}
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 2; i++) {
new Thread(()->{
for (int j = 0; j < 25; j++) {
c.put(Thread.currentThread().getName() + " " + j);
}
}, "p" + i).start();
}
}
}
十五、Demo15
1、RLDemo1
package com.hskw.demo15;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class RLDemo1 {
/**
* reentrantlock用于替代synchronized
* 使用reentrantlock可以完成同样的功能
* reentrantlock必须要手动释放锁
* 使用syn锁定的话如果遇到异常,jvm会自动释放锁,但是lock必须手动释放锁,
* 因此经常在finally中进行锁的释放
*/
Lock lock = new ReentrantLock();
public void test1(){
try {
lock.lock();//this
for (int i = 0; i < 3; i++) {
System.out.println(i);
TimeUnit.SECONDS.sleep(1);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void test2(){
lock.lock();
System.out.println("test 2...");
lock.unlock();
}
public static void main(String[] args) {
RLDemo1 rlDemo1 = new RLDemo1();
new Thread(rlDemo1::test1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(rlDemo1::test2).start();
}
}
2、RLDemo2
package com.hskw.demo15;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class RLDemo2 {
Lock lock = new ReentrantLock();
public void test1(){
try {
lock.lock();
for (int i = 0; i < 2; i++) {
System.out.println(i);
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
/**
* 使用reentrantlock可以进行“尝试锁定”tryLock,这样无法锁定,或者在指定时间内无法锁定,
* 线程可以决定是否继续等待
* 可以使用tryLock进行尝试锁定,不管锁定与否,方法都将继续执行
* 可以根据tryLock的返回值来判定是否锁定
* 也可以指定tryLock的时间,由于tryLock(time)抛出异常,所以要注意unclock的处理,必须放到finally中
*/
public void test2(){
boolean locked = false;
try {
locked = lock.tryLock(3, TimeUnit.SECONDS);
System.out.println("test2...." + locked);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if (locked) {
System.out.println("test2 end");
lock.unlock();
}
}
}
public static void main(String[] args) {
RLDemo2 rlDemo2 = new RLDemo2();
new Thread(rlDemo2::test1).start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(rlDemo2::test2).start();
}
}
3、RLDemo3
package com.hskw.demo15;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
public class RLDemo3 {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(()->{
try {
lock.lock();
System.out.println("t1 start");
TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
System.out.println("t1 end");
} catch (InterruptedException e) {
System.out.println("interrupted!");
} finally {
lock.unlock();
}
});
t1.start();
Thread t2 = new Thread(()->{
boolean locked = false;
try {
//lock.lock();
//使用lockInterruptibly来锁定可以对Interrupt方法作出响应
lock.lockInterruptibly();
System.out.println("t2 start");
TimeUnit.SECONDS.sleep(5);
System.out.println("t2 end");
locked = true;
} catch (InterruptedException e) {
System.out.println("interrupted!");
} finally {
if (locked){
lock.unlock();
}
}
});
t2.start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.interrupt();
}
}
4、RLDemo4
package com.hskw.demo15;
import java.util.concurrent.locks.ReentrantLock;
public class RLDemo4 extends Thread{
//ReentrantLock可以指定是否为公平锁,true为公平,默认为false
private static ReentrantLock lock = new ReentrantLock(true);
@Override
public void run() {
for (int i = 0; i < 100 ; i++) {
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "获得锁");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
RLDemo4 rlDemo4 = new RLDemo4();
Thread t1 = new Thread(rlDemo4);
Thread t2 = new Thread(rlDemo4);
t1.start();
t2.start();
}
}
是你跟在我身后太久了,看不到我所看到的景象。 ———— 山鬼谣