java中Thread的深入了解(二)

一.synchronized方法和synchronized代码块

synchronized方法 只有一个线程能访问,只有这个方法执行完之后其他线程才能访问

synchronized方法的锁是当前对象,也就是如果new多次是不能阻止多个线程访问代码的

public classSyncTest {

/**

*对于SyncTest的对象 只有一个线程能访问

*对于不同的SyncTest的对象可以有多个线程访问

*/

public synchronized void say1(){

System.out.println("hello get the lock1!");

//休眠200s不释放锁

try{

Thread.sleep(200*1000);

}catch(InterruptedException e) {

e.printStackTrace();}

}

/**

* 与synchronized方法相同

*/

public void say2(){

synchronized(this){

System.out.println("hello get the lock2!");

try{

Thread.sleep(200*1000);

}catch(InterruptedException e) {

e.printStackTrace();}

}

}

/**

* 同一时间只有一个线程能访问

* 与synchronized方法不同,这样即使多次new也跟使用同一个对象是一样的 只有一个线程能访问

**/

public void say3(){

synchronized(SyncTest.class){

System.out.println("hello get the lock3!");

try{

Thread.sleep(200*1000);

}catch(InterruptedException e) {

e.printStackTrace();}

}

}

}

测试运行同步方法和同步代码块:

synchronized方法和synchronized代码块的三种测试

1.测试say1()方法发现刚开始时只打印了一段,而说明只有一个线程访问了。

测试say1()方法

2.同步方法默认是锁当前类对象,在多次new的时候,并不能起到锁方法的作用。

测试say1()方法

3.同步代码段可以锁类,这样即使多次new也跟使用同一个对象是一样的,只有一个线程能访问。

测试say3()方法

举例子:

最为线程安全类 最常见的做法就是加synchronized方法

StringBuilder 线程不安全

StringBuffer  线程安全:看StringBuffer源码,可以看见 所有方法都加了synchronized

HashMap线程不安全

HashTable 线程安全


二.Thread类常用方法

名称 new Thread(String name)   和 new Thread(Runnable run,String name)

获取当前: Thread Thread.current();

获取当前所有Thread的数量:Thread.activeCount();

eg:

测试结果

三.线程变量ThreadLocal

ThreadLocal是一个特殊的模板变量 每个线程获取到的都是自己的值,看源码就知道 其实是利用了Thread.currentThread(),然后利用了 map结构存储,所以ThreadLocal中的map map.get(Thread.currentThread()); 返回的就是不同的值。

public class ThreadLocalTest{    

private static ThreadLocal<ThreadLocalTest> threadLocal=new ThreadLocal<>();;

private static ThreadLocaTest mainThreadLocal;

/**

* 创建当前线程的ThreadLocal对象

*/

public static void prepare(){

if(threadLocal.get()==null){

threadLocal.set(new ThreadLocalTest());

}

}

public static void prepareMain(){

if(mainThreadLocal!=null){

throw new RuntimeException("只有一个线程可以调用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(){

}

}

public static  voidshowThreadLocal(){

ThreadLocalTest.prepareMain();

new Thread(new Runnable() {

@Override

public void run() {

if(ThreadLocalTest.getMain()!=ThreadLocalTest.myThreadTest()){

console.info(Thread.currentThread().getName()+"当前不是主线程");

}else{

console.info(Thread.currentThread().getName()+"当前是主线程");

}

}

}).start();

if(ThreadLocalTest.getMain()!=ThreadLocalTest.myThreadTest()){

console.info(Thread.currentThread().getName()+"当前不是主线程");

}else{

console.info(Thread.currentThread().getName()+"当前是主线程");

}

}


输出结果

其实现原理 利用的是Thread.currentThread();

四.concurrent包的CountDownLatch

一个辅助类,初始化的时候指定数据个数,没调用一次countDown()数字减少一个。

一个方法 countDown() 一个方法await()。

public static void CountDownLatchTests() throws InterruptedException {

long startTime=System.currentTimeMillis();

CountDownLatch countDownLatch=new CountDownLatch(65535);

ThreadPool threadPool=new ThreadPool(10000);

for(inti=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");

}


eg:线程A , B ,C。 A,B运行完后运行C

CountDownLatch countDownLatch=new CountDownLatch(2);

new Thread(newRunnable() {

@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);

ThreadPool threadPool=new ThreadPool(10000);

for(inti=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");

上面的代码预计消耗时间是200ms但是 实际远远超出了我们的预期,这是因为新建线程消耗了一部分时间,cpu拥挤,并不会有那么多线程同时运行,会排队一会。

通过线程池可以优化上述代码的速度:

public class IdleThread extends Thread {   

 public LinkedBlockingQueuequeue;   

 public boolean started = true;    

public IdleThread(LinkedBlockingQueuequeue) {

this.queue = queue;

}

@Override

public void run() {

while (started) {

try {

//这个poll表示获取一个Runnable如果没有等待100ms

Runnable runnable = queue.poll(100, TimeUnit.MILLISECONDS);

if(runnable!=null)

runnable.run();

} catch (InterruptedException e) {

}

}

}

public void kill() {

started = false;

}

}

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(inti=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();

}

}

}

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,493评论 18 399
  • 本文主要讲了java中多线程的使用方法、线程同步、线程数据传递、线程状态及相应的一些线程函数用法、概述等。 首先讲...
    李欣阳阅读 2,426评论 1 15
  • Java多线程学习 [-] 一扩展javalangThread类 二实现javalangRunnable接口 三T...
    影驰阅读 2,941评论 1 18
  • 文章来源:http://www.54tianzhisheng.cn/2017/06/04/Java-Thread/...
    beneke阅读 1,461评论 0 1
  • 文/雨竹 昨日与朋友小酌,多贪几杯,昏昏然睁开眼已到天亮,掀开窗帘,纷纷洒洒的雪花朦胧着眼前的一切,冬的气息越来...
    辽宁_雨竹阅读 353评论 1 3