资讯专栏INFORMATION COLUMN

JAVA多线程

wdzgege / 1017人阅读

摘要:引起线程之间执行顺序的是竞争条件。只有资源共享才会有线程安全的问题线程资源同步和线程之间的同步。对于方法或者代码块,当出现异常时,会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象。执行器执行器是实现的线程池。

package com.test;

public class MyThread  extends   Thread{
    @Override
    public void run() {
        System.out.println("新的线程开始运行");
    }
    public static void main(String[] args) {
        System.out.println("main的主线程");
        new  MyThread().start();
        //start方法调用以后,那么此时CPU有可能先执行新的线程。也有可能继续执行原来的线程(执行后续的代码)
        System.out.println("main的主线程");
    }
}
public class MyThread  extends   Thread{
    @Override
    public void run() {
        System.out.println("新的线程开始运行");
    }
    public static void main(String[] args) {
        
         System.out.println("main的主线程");
         Thread  t=    new  MyThread();
         System.out.println(t.getState());
         t.start();
         System.out.println(t.getState());
            try {
            Thread.sleep(5000);
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
        System.out.println(t.getState());
        t.start();  //只有线程状态是NEW才可以调用start方法。
    }
}

引起线程之间执行顺序的是竞争条件。

package com.spring;

public class MyThread  extends   Thread{
    public  int  count=0;
    @Override
    public void run() {
          count++;
        
    }
    
    public  void   countAdd(){
        
        this.count++;
    }
    public static void main(String[] args) {
        
        
        System.out.println("main的主线程");
        MyThread  t=    new  MyThread();
        t.setPriority(MAX_PRIORITY);
       t.start();
       
       t.countAdd();
      System.out.println(t.count);
      System.out.println(t.count);
      System.out.println(t.count);
      System.out.println(t.count);
      System.out.println(t.count);
    }

}

并非只有静态变量才会有线程不安全,如上,如果count++不是原子操作的话,成员变量依然会不安全。因为资源是共享的,而run方法却在不同的线程中运行。

线程在真正执行的时候完全不是按照一条语句一条语句的执行。
比如:
if(count>0)
只要资源不共享,断续着的切换执行根本没有问题。只有资源共享才会有线程安全的问题
线程资源同步和线程之间的同步。
线程之间的同步就是比如A执行完之后要执行B,然后执行C。就是在线程之间有顺序的执行。

等待与阻塞:
等待是等待另外一个线程出现结果,或者另一个线程的调度,阻塞是没有获得锁
守护线程:
与守护进程是有区别的。当没有工作线程的时候,就停止了。
wait方法等待并释放这个锁。
对于synchronized方法或者synchronized代码块,当出现异常时,JVM会自动释放当前线程占用的锁,因此不会由于异常导致出现死锁现象。
有时候你会看到有所谓的类锁和对象锁的说法。
`假设我有一个类ClassA,其中有一个方法synchronized methodA(),那么当这个方法被调用的时候你获得就是对象锁,但是要注意,如果这个类有两个实例,比如:
ClassA a = new ClassA();
ClassA b = new ClassA();
那么如果你在a这对象上调用了methodA,不会影响b这个对象,也就是说对于b这个对象,他也可以调用methodA,因为这是两对象,所以说对象锁是针对对象的。`
在这里主要讨论一个使用上的问题,当我们使用sychronized锁住某个对象时,我们锁住的是这个引用本身,还是内存(堆)中的这个对象本身。对这个问题的一个延伸是,当我们在sychronized作用区域内,为这个引用附一个新值的时候,sychronized是否还有效?
先给出结论,sychronized锁住的是内存(堆)中的对象,当引用被附上新值的时候,则相当于旧对象的锁被释放。这里不做理论讨论,只是用程序进行验证。
http://www.cnblogs.com/shipengzhi/articles/2223100.html
static synchronized 锁住的是整个类。会影响到所有的实例。

执行器

执行器是Java实现的线程池。

package com.ex;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class Server {
    
    private   ThreadPoolExecutor  executor;
  
    public  ThreadPoolExecutor getExecutor(){
        return  this.executor;
    }
    
    
    public  Server(){
        
//        executor=(ThreadPoolExecutor) Executors.newCachedThreadPool();// cache线程池在真正有任务的时候才初始化,随着任务变化而变化
        executor=(ThreadPoolExecutor) Executors.newFixedThreadPool(10);//固定任务的线程池
        System.out.println("总共线程池------------------------"+executor.getPoolSize());
        System.out.println("活动的线程池数量---------------------"+executor.getActiveCount());
    }
    
    public  void  excuteTask(Task  task){
          executor.execute(task);
          System.out.println("一共得线程池"+executor.getPoolSize());
            System.out.println("活动的线程池数量,即正在处理任务的线程数量"+executor.getActiveCount());
    }

    public static void main(String[] args) {
        Server  server=new Server();
        for(int i=0;i<100;i++){
            Task  task=new Task("线程id"+i);
            server.excuteTask(task);
        }
        //主线程不断询问线程组是否执行完毕
        while(true){
            
            if(server.getExecutor().getCompletedTaskCount()==100){
                System.out.println("总共线程池------------------------"+server.getExecutor().getPoolSize());
                System.out.println("活动的线程池数量---------------------"+server.getExecutor().getActiveCount());
                server.getExecutor().shutdown();
                break;
            }
        }
        
    }

}


package com.ex;

import java.util.Date;

public class Task  implements  Runnable{
    
    private  String  name;
    private  Date  date;
    
    public  Task(String name){
        this.date=new Date();
        this.name=name;

    }
    

    @Override
    public void run() {
    
        try {
            System.out.println(this.name+"----开始执行任务");
            Thread.sleep((long) (Math.random()*1000));
            System.out.println(this.name+"----结束执行任务");
        } catch (InterruptedException e) {
            
            e.printStackTrace();
        }
        
    }

}
线程的内存模型

对于公共变量或者资源,线程会复制一份到属于自己的线程栈,操作以后再放回公共资。在复制的过程中间,如果有其他线程修改了资源,那么复制的就不是最新的。这就是所谓的内存可见性问题。同步了当然不会存在这样的问题,因为同一个时刻,另外一个线程必读等待另一个线程读写完毕。

/**
 *===============================================================
 * @CopyRight:    北京逸生活技术服务有限公司技术部
 * @author:       xujianxing
 * @date:        2016年3月16日
 * @version:      1.0.0
 *===============================================================
 * 修订日期                                                         修订人                                                    描述
 */


package syncdemo;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

/**
 * 

TODO *

TODO * @author xujinaxing * @date 2016年3月16日 * @see * @since * @modified TODO */ public class ThreadUnSafe extends Thread{ public static int flag=0; public static List list=new ArrayList(); @Override public void run() { // TODO Auto-generated method stub super.run(); flag++; //添加的时候必须同步。也就是说保证list是内存可见的。 synchronized (list) { list.add(flag); } System.out.println(flag); } public static void main(String[] args) { for(int i=0;i<10000;i++){ new ThreadUnSafe().start(); } try { Thread.currentThread().sleep(15000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } int size=new HashSet(ThreadUnSafe.list).size(); System.out.println("size"+size); } }

打印的值是9991.说明了线程之间由于存取不及时。导致set的size小于1000.

/**
 *===============================================================
 * @CopyRight:    北京逸生活技术服务有限公司技术部
 * @author:       xujianxing
 * @date:        2016年3月16日
 * @version:      1.0.0
 *===============================================================
 * 修订日期                                                         修订人                                                    描述
 */


package syncdemo;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 

TODO *

TODO * @author xujinaxing * @date 2016年3月16日 * @see * @since * @modified TODO */ public class ThreadSafe extends Thread{ public static AtomicInteger flag=new AtomicInteger(0); public static List list=new ArrayList(); @Override public void run() { // TODO Auto-generated method stub super.run(); int i=flag.incrementAndGet(); synchronized (list) { list.add(i); } System.out.println(flag.get()); } public static void main(String[] args) { for(int i=0;i<20000;i++){ new ThreadSafe().start(); } try { Thread.currentThread().sleep(15000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } int size=new HashSet(ThreadSafe.list).size(); System.out.println("size"+size); } }

上面的这个代码是线程安全的。性能高,是李利用硬件提供的原子操作。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64343.html

相关文章

  • Java线程学习(一)Java线程入门

    摘要:最近听很多面试的小伙伴说,网上往往是一篇一篇的多线程的文章,除了书籍没有什么学习多线程的一系列文章。将此线程标记为线程或用户线程。 最近听很多面试的小伙伴说,网上往往是一篇一篇的Java多线程的文章,除了书籍没有什么学习多线程的一系列文章。但是仅仅凭借一两篇文章很难对多线程有系统的学习,而且面试的时候多线程这方面的知识往往也是考察的重点,所以考虑之下决定写一系列关于Java多线程的文章...

    Donne 评论0 收藏0
  • Java线程专题一:并发所面临的问题

    摘要:但是并不是什么多线程就可以随便用,有的时候多线程反而会造成系统的负担,而且多线程还会造成其他的数据问题,下面就来介绍一下多线程面临的问题。下面这张图是多线程运行时候的情况,我们发现上下文切换的次数暴增。 并发的概念: 在Java中是支持多线程的,多线程在有的时候可以大提高程序的速度,比如你的程序中有两个完全不同的功能操作,你可以让两个不同的线程去各自执行这两个操作,互不影响,不需要执行...

    madthumb 评论0 收藏0
  • Java线程可以分组,还能这样玩!

    摘要:如图所示,带有的所有线程构造方法都可以定义线程组的。线程组还能统一设置组内所有线程的最高优先级,线程单独设置的优先级不会高于线程组设置的最大优先级。 前面的文章,栈长和大家分享过多线程创建的3种方式《实现 Java 多线程的 3 种方式》。 但如果线程很多的情况下,你知道如何对它们进行分组吗? 和 Dubbo 的服务分组一样,Java 可以对相同性质的线程进行分组。 来看下线程类 Th...

    biaoxiaoduan 评论0 收藏0
  • JAVA 线程和并发基础

    摘要:线程可以被称为轻量级进程。一个守护线程是在后台执行并且不会阻止终止的线程。其他的线程状态还有,和。上下文切换是多任务操作系统和多线程环境的基本特征。在的线程中并没有可供任何对象使用的锁和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻译:并发编程网 - 郑旭东 校对:方腾飞 多...

    vboy1010 评论0 收藏0
  • Java线程学习(七)并发编程中一些问题

    摘要:相比与其他操作系统包括其他类系统有很多的优点,其中有一项就是,其上下文切换和模式切换的时间消耗非常少。因为多线程竞争锁时会引起上下文切换。减少线程的使用。很多编程语言中都有协程。所以如何避免死锁的产生,在我们使用并发编程时至关重要。 系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)syn...

    dingding199389 评论0 收藏0
  • 学习Java线程的一些总结

    摘要:多线程环境下的一些问题安全性问题在没有正确同步的情况下,多线程环境下程序可能得出错误的结果。一些相关概念竞争条件多线程的环境下,程序执行的结果取决于线程交替执行的方式。而线程的交替操作顺序是不可预测的,如此程序执行的结果也是不可预测的。 入口 Java多线程的应用复杂性之如jvm有限的几个内存方面的操作和规范,就像无数纷繁复杂的应用逻辑建立在有限的指令集上。 如何写出线程安全的程序,有...

    coolpail 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<