synchronized方法和synchronized代碼段
synchronized方法 只有一個線程能訪問箱亿,只有這個方法執(zhí)行完之后其他線程才能訪問
synchronized方法的鎖是當(dāng)前對象,也就是如果new多次是不能阻止多個線程訪問代碼的
public class SyncTest {
/**
* 對于SyncTest的對象 只有一個線程能訪問
* 對于不同的SyncTest的對象可以有多個線程訪問
*/
public synchronized void say(){
System.out.println("hello get the lock!");
//休眠200s 不釋放鎖
try {
Thread.sleep(200 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 與synchronized方法相同
*/
public void say(){
synchronized(this) {
System.out.println("hello get the lock!");
//休眠200s 不釋放鎖
try {
Thread.sleep(200 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 同一時間只有一個線程能訪問
* 與synchronized方法不同
**/
public void say(){
synchronized(SyncTest.class) {
System.out.println("hello get the lock!");
//休眠200s 不釋放鎖
try {
Thread.sleep(200 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
最為線程安全類 最常見的做法就是加synchronized方法
StringBuilder
StringBuffer
HashTable
HashMap
Thread類常用方法
名稱 new Thread(String name) new Thread(Runnable run,String name)
獲取當(dāng)前Thread Thread.currentThread();
獲取當(dāng)前所有Thread的數(shù)量 Thread.activeCount();
線程變量ThreadLocal
ThreadLocal是一個特殊的模板變量 每個線程獲取到的都是自己的值
public class ThreadLocalTest{
private static ThreadLocal<ThreadLocalTest> threadLocal=new ThreadLocal<>();
private static ThreadLocalTest mainThreadLocal;
/**
* 創(chuàng)建當(dāng)前線程的ThreadLocal對象
*/
public static void prepare(){
if(threadLocal.get()==null){
threadLocal.set(new ThreadLocalTest());
}
}
/**
* 主線程中調(diào)用
*/
public static void prepareMain(){
if(mainThreadLocal!=null){
throw new RuntimeException("只有一個線程可以調(diào)用prepareMain");
}
mainThreadLocal=new ThreadLocalTest();
if(threadLocal.get()==null){
threadLocal.set(mainThreadLocal);
}
}
public static ThreadLocalTest getMain(){
return mainThreadLocal;
}
public static ThreadLocalTest myThreadTest(){
return threadLocal.get();
}
private ThreadLocalTest(){
}
}
其實現(xiàn)原理 利用的是Thread.currentThread();
concurrent包的CountDownLatch
一個輔助類惠爽,初始化的時候指定數(shù)據(jù)個數(shù),沒調(diào)用一次countDown()數(shù)字減少一個
await方法會阻塞 直到CountDownLatch里的數(shù)字為0
CountDownLatch countDownLatch=new CountDownLatch(100);
for(int i=0;i<100;i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(200);
System.out.println(Thread.currentThread().getName()+" done!");
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有線程完成了!");
線程A , B ,C雷恃。 A,B運行完后運行C
CountDownLatch countDownLatch=new CountDownLatch(2);
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" done !");
countDownLatch.countDown();
}
},"A").start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" done !");
countDownLatch.countDown();
}
},"B").start();
new Thread(new Runnable() {
@Override
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" done !");
}
},"C").start();
線程池初步
long startTime=System.currentTimeMillis();
CountDownLatch countDownLatch=new CountDownLatch(65535);
for(int i=0;i<65535;i++){
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(200);
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有線程完成了!"+(System.currentTimeMillis()-startTime)+"ms");
上面的代碼預(yù)計消耗時間是200ms但是 實際遠(yuǎn)遠(yuǎn)超出了我們的預(yù)期疆股,這是因為新建線程消耗了一部分時間,cpu擁擠倒槐,并不會有那么多線程同時運行旬痹,會排隊一會。
通過線程池可以優(yōu)化上述代碼的速度
/*
* 空閑線程
*/
public class IdleThread extends Thread {
public LinkedBlockingQueue<Runnable> queue;
public boolean started = true;
public IdleThread(LinkedBlockingQueue<Runnable> queue) {
this.queue = queue;
}
@Override
public void run() {
while (started) {
try {
Runnable runnable = queue.poll(100, TimeUnit.MILLISECONDS);
if(runnable!=null)
runnable.run();
} catch (InterruptedException e) {
}
}
}
public void kill() {
started = false;
}
}
/**
* 基礎(chǔ)線程池
*/
public class ThreadPool {
/**
* 池最小大小
*/
private int minSize;
/**
* 池最大大小
*/
private int maxSize;
LinkedBlockingQueue<Runnable> tasks;
List<IdleThread> idleThreads;
public ThreadPool(int size){
this.maxSize=size;
this.minSize=size;
init();
}
private void init(){
tasks=new LinkedBlockingQueue<>(minSize);
idleThreads=new ArrayList<>(minSize);
for(int i=0;i<minSize;i++){
IdleThread thread=new IdleThread(tasks);
idleThreads.add(thread);
thread.start();
}
}
public void execute(Runnable runnable) throws InterruptedException {
tasks.put(runnable);
}
public void shutdown(){
try {
for (IdleThread idleThread : idleThreads) {
idleThread.kill();
idleThread.interrupt();
}
}catch (Exception e){
e.printStackTrace();;
}
tasks.clear();
}
public void waitForAll(){
while(tasks.size()>0){
try {
Thread.sleep(0,1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
通過上述兩類 重寫一下上面的代碼
long startTime=System.currentTimeMillis();
CountDownLatch countDownLatch=new CountDownLatch(65535);
ThreadPool threadPool=new ThreadPool(9000);
for(int i=0;i<65535;i++){
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(200);
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
try {
countDownLatch.await();
threadPool.shutdown();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有線程完成了!"+(System.currentTimeMillis()-startTime)+"ms");
可以看到速度比那個優(yōu)化很多