多线程一直是Java的一个重点和难点,前两天小结了一下。
synchronized和Lock
我们都知道ArrayList是非线程安全的,就拿它开刀。下面这个程序简单地展示了synchronized和Lock的用法。
package temp.test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by 10033 on 2017/5/10.
*/
public class ArrayListThreadTest {
public static Lock lock=new ReentrantLock();
public static List list=new ArrayList();
public static int doRun(int cou) {
while(cou<100000) {
//非同步方法 要么死循环 要么抛异常
/*list.add(10);
++cou;*/
//两种同步方式
/*synchronized (list) {
list.add(10);
++cou;
}*/
lock.lock();
list.add(10);
++cou;
lock.unlock();
}
return cou;
}
public static void main(String[] args) {
Thread1 thread1=new Thread1();
Thread2 thread2=new Thread2();
thread1.start();
thread2.start();
while(thread1.cou+thread2.cou<200000) {
System.out.println(thread1.cou+thread2.cou);
}
System.out.println(list.size() + " @@@@");
System.out.println(thread1.cou+thread2.cou + " ####");
}
}
class Thread1 extends Thread {
public int cou=0;
@Override
public void run() {
this.cou=ArrayListThreadTest.doRun(cou);
}
}
class Thread2 extends Thread {
public int cou=0;
@Override
public synchronized void run() {
this.cou=ArrayListThreadTest.doRun(cou);
}
}
如果不用同步,那么这个程序要么死循环,要么抛数组下标溢出异常。
tryLock
package temp.test;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by 10033 on 2017/5/10.
*/
public class LockTest {
public static Lock lock=new ReentrantLock();
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
boolean flag=false;
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
// if(lock.tryLock(1, TimeUnit.SECONDS)) { //设置时间来获得锁 超时则放弃
if(lock.tryLock()) { //第一次没得到就放弃
flag=true;
} else {
System.out.println("没获得锁");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if(flag) { //确定锁上了才解锁
lock.unlock();
System.out.println("解锁啦");
}
}
}
}).start();
new Thread(new Runnable() {
public void run() {
lock.lock();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("解锁~~~~");
lock.unlock();
}
}).start();
}
}
lock和tryLock的一个不同是lock是阻塞等待锁资源,而tryLock则是试一试(和它名字一样),如果不行,就放弃。
lockInterruptibly
package temp.test;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by 10033 on 2017/5/11.
*/
public class LockInterruptiblyTest {
public static Lock lock=new ReentrantLock();
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(new Runnable(){
@Override
public void run() {
try {
// Thread.sleep(3000);
lock.lockInterruptibly();
System.out.println("No Exeception");
while(true);
// for(int i=0;i<1000000;i++);
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println(Thread.currentThread().getName()+" interrupted.");
} finally {
lock.unlock();
}
}
});
t1.start();
t1.interrupt();//中断则锁抛异常
// Thread.sleep(1000);
}
}
这个和lock一样也是个愣头青,阻塞等待锁,但它所在的线程一旦收到中断信号,它就抛异常。
interrupt
说到中断,那就讲一下interrupt。
package temp.test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by 10033 on 2017/5/11.
*/
public class InterruptTest {
public static String lock="";
public static Lock locked=new ReentrantLock();
public static Condition condition=locked.newCondition();
public static void main(String[] args) throws InterruptedException {
Thread t1=new Thread(new Runnable() {
@Override
public void run() {
/*synchronized (lock) {
for(int i=0;i<10;i++)
System.out.println("@@");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<10;i++)
System.out.println("##");
}*/
locked.lock();
for(int i=0;i<10;i++)
System.out.println("@@");
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<10;i++)
System.out.println("##");
locked.unlock();
}
});
t1.start();
Thread.sleep(1000);
t1.interrupt();//唤醒阻塞但抛中断异常
/*synchronized (lock) { //唤醒阻塞不抛异常 wait会主动放弃锁资源
lock.notify();
}*/
/*locked.lock();
condition.signal();
locked.unlock();*/
}
}
它就是改变一个状态值,它能唤醒阻塞线程(被sleep和wait的),但会抛中断异常。这里还要说一点,那就是wait和notify方法都得在使用该方法的对象的synchronized同步代码块里使用。如:
signal和await
我们都知道Object有wait,notify,notifyAll三个方法,而在Lock机制里,同样有对应的await,signal,signalAll。
package temp.test;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created by 10033 on 2017/5/10.
*/
/**
* await和signal必须放在lock之后
*/
public class SignalAndAwait {
public static Lock lock=new ReentrantLock();
//两个Condition来自同一把锁
public static Condition condition1=lock.newCondition();
public static Condition condition2=lock.newCondition();
public static void main(String[] args) {
new Thread(new Runnable() {
public void run() {
for(int i=0;i<50;i++) {
lock.lock();
condition2.signal();
System.out.println("Thread1");
try {
condition1.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
lock.lock();
condition2.signal();
lock.unlock();
}
}).start();
new Thread(new Runnable() {
public void run() {
for(int i=0;i<50;i++) {
lock.lock();
condition1.signal();
System.out.println("Thread2");
try {
condition2.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
lock.lock();
condition1.signal();
lock.unlock();
}
}).start();
}
}
这三个方法也必须放在它们对应的lock里执行,即获得锁资源后才能执行,不然会抛异常。
yield和join
yield:将当前线程由运行变为就绪。
join:阻塞当前线程,自己开启的线程先运行完再说。
可以看注释,注释写得比较详细
YieldTest
package threadTest;
/**
* Created by 10033 on 2017/5/19.
*/
public class YieldTest {
public static void main(String[] args) {
new Thread(new T1()).start();
new Thread(new T2()).start();
}
}
class T1 implements Runnable {
@Override
public void run() {
System.out.println("T1~~~~~");
Thread.yield(); //从运行到就绪 如果对方线程不争气阻塞了 那我也不客气 接着运行
System.out.println("T1@@@@@");
}
}
class T2 implements Runnable {
@Override
public void run() {
System.out.println("T266666");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T2T2T2");
}
}
JoinTest
package threadTest;
/**
* Created by 10033 on 2017/5/19.
*/
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
/*Thread t2=new Thread(new T4());
// t2.join(); //放在start之前并不会抛异常 但没join效果
t2.start();
t2.join(); //我加入了我就是老大 等我运行完后面的程序才能运行
new Thread(new T3()).start();*/
new Thread(new T3()).start(); //内部有join 说明join只影响当前线程
new Thread(new T4()).start();
}
}
class T3 implements Runnable {
@Override
public void run() {
System.out.println("T1~~~~~");
System.out.println("T1@@@@@");
}
}
class T4 implements Runnable {
@Override
public void run() {
System.out.println("T266666");
Thread t=new Thread() {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("success");
}
};
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
/*try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
System.out.println("T2T2T2");
}
}