ReentrantLock
Synchronized锁
例:
synchronized void m1(){ for (int i = 0; i < 10; i++) { try { TimeUnit.SECONDS.sleep(1);//睡1秒 }catch (InterruptedException e){ e.printStackTrace(); } System.out.println(i); } } synchronized void m2(){ System.out.println("m2......"); } public static void main(String[] args) { ReentrantLock1 r1 = new ReentrantLock1(); new Thread(r1 :: m1).start();//开启线程 try { TimeUnit.SECONDS.sleep(1); }catch (InterruptedException e){ e.printStackTrace(); } new Thread(r1 :: m2).start(); }
上面的例程是使用Synchronized锁,下面将它改写为ReentrantLock
Lock lock = new ReentrantLock();
void m1(){
try {
lock.lock();//相当于synchronized(this)
for (int i = 0; i < 10; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println(i);
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
void m2(){
lock.lock();
System.out.println("m2.....");
lock.unlock();
}
public static void main(String[] args) {
ReentrantLock2 r2 = new ReentrantLock2();
new Thread(r2 :: m1).start();
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
new Thread(r2 :: m2).start();
}
对比之后发现,ReentrantLock比Synchronized锁多了手动释放的过程
tryLock
tryLock返回一个boolean类型的值,当前线程尝试是否能够得到锁,能够得到返回true,不能得到返回false
Lock lock = new ReentrantLock();
void m1(){
lock.lock();
try {
for (int i = 0; i < 100; i++) {
TimeUnit.SECONDS.sleep(1);
System.out.println(i);
}
}catch (InterruptedException e){
e.printStackTrace();
}finally {
lock.unlock();
}
}
void m2(){
boolean locked = false;
try {
locked = lock.tryLock(5,TimeUnit.SECONDS);//尝试看是否能够得到锁(5秒)
System.out.println(locked ? "拿到锁" : "没有拿到锁");
}catch (InterruptedException e){
e.printStackTrace();
}finally {
if (locked) lock.unlock();
}
}
public static void main(String[] args) {
ReentrantLock3 r3 = new ReentrantLock3();
new Thread(r3 :: m1).start();
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
new Thread(r3 :: m2).start();
}
lockInterruptibly
当前线程等待其他线程使用完锁,如果其他线程一直在使用锁,会造成程序一直卡住,此时使用lockInterruptibly进行打断
public static void main(String[] args) {
Lock 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(() ->{
try {
// lock.lock();
lock.lockInterruptibly(); //可以对interrupt()方法做出响应
System.out.println("t2 start");
TimeUnit.SECONDS.sleep(5);
System.out.println("t2 end");
}catch (InterruptedException e){
e.printStackTrace();
}finally {
if(((ReentrantLock) lock).isHeldByCurrentThread()) lock.unlock();
}
});
t2.start();
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
t2.interrupt(); //打断线程2的等待
}
设置公平锁
ReentrantLock支持设置公平锁
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() + "获得锁");
}finally {
lock.unlock();
}
}
}
public static void main(String[] args) {
ReentrantLock5 r5 = new ReentrantLock5();
Thread th1 = new Thread(r5);
Thread th2 = new Thread(r5);
th1.start();
th2.start();
}
生产者消费者
使用wait和notify实现
public class MyContainer<T>{
final private LinkedList<T> lists = new LinkedList<>();
final private int MAX = 10;//最多10个元素
private int count = 0;
public synchronized void put(T t){
while(lists.size() == MAX){ //why while not if?
try{
this.wait(); //容器满了,让生产者线程等待
}catch(InterruptedException e){
e,printStackTrace();
}
}
lists.add(t);
++count;
this.notifyAll();//唤醒所有消费线程
}
public synchronized T get(){
while(lists.size() == 0){
try{
this.wait(); //容器空了,让所有的消费者线程等待
}catch(InterruptdException e){
e.printStackTrace();
}
}
T first = lists.removeFirst();
count--;
this.notifyAll();//通知生产者线程进行生产
return first;
}
public static void main(String[] args){
MyContainer<String> lists = new MyContainer<>();
//开启消费者线程
for(int i = 0;i < 10;i++){
new Thread(()->{
for(int j = 0;j < 100;j++)
System.out.println(lists.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++)
lists.put(Thread.currentThread().getName() + " " + j);
},"p" + i).start();
}
}
}
使用Lock和condition实现
public class Container2<T>{
final private LinkedList<T> lists = new LinkedList<>();
final private int MAX = 10;
private int count = 0;
private Lock lock = new ReentrantLock();
private Condition consumer = lock.newCondition();
private Condition producer = lock.newCondition();
public void put(T t){
try{
lock.lock();
while(lists.size() == MAX){
producer.await();
}
lists.add(t);
++count;
consumer.signalAll
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
}
public T get(){
T first = null;
try{
lock.lock();
while(lists.size() == 0){
consumer.await();
}
T first = lists.removeFirst();
count--;
producer.signalAll();
}catch(InterruptedException e){
e.printStackTrace();
}finally{
lock.unlock();
}
return first;
}
}
ThreadLocal
可以让每个线程的内容独享,其他线程无法使用
synchronized是时间换空间,等到前面的线程执行完后才能执行。
ThreadLocal是空间换时间,每个对象都是独立的
例程:
public class ThreadLocal1 {
volatile static Person p = new Person();
public static void main(String[] args) {
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(p.name);
}).start();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
p.name = "lisi";
}).start();
}
}
class Person{
String name = "zhangsan";
}
public class ThreadLocal2 {
static ThreadLocal<Person> tl = new ThreadLocal<>();
public static void main(String[] args) {
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(2);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(tl.get());
}).start();
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
tl.set(new Person());
}).start();
}
static class Person{
String name = "zhangsan";
}
}