多线程

1. 获取线程相关信息的方法

        //获取当前正在执行的线程
        Thread main = Thread.currentThread();

        //获取线程的名字
        String name = main.getName();
        
        //获取唯一标识
        long id = main.getId();
        
        //获取线程优先级
        int priority = main.getPriority();
        
        //显示是否处于活动状态
        boolean isAlive = main.isAlive();

        //是否为守护线程
        boolean isDaemon = main.isDaemon();

        //是否被中断了
        boolean isInterrupted = main.isInterrupted();

 2. 常用方法
void join()  等待该线程终止。调用该方法的线程会进入阻塞状态,直到该线程结束才会解除阻塞。

void join(long millis)  等待该线程终止的时间最长为 millis 毫秒。

/*
         * JDK1.8之前有一个要求:
         * 当一个方法的局部内部类中想引用这个方法的
         * 其它局部变量时,该变量要求必须是final的.
         * 这是JVM内存分配导致的一个问题,在JDK1.8
         * 之后不再有.
         * 例如:
         * main方法中的局部内部类show当中想引用
         * main方法的一个局部变量download,那么
         * 该变量必须是final的.
         *
         */
        final Thread download = new Thread(){
            public void run(){
                System.out.println("down:开始下载图片...");
                for(int i=1;i<=100;i++){
                    System.out.println("down:"+i+"%");
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println("down:下载完毕!");
                isFinish = true;
            }
        };
        
        
        Thread show = new Thread(){
            public void run(){                
                System.out.println("show:开始显示图片...");
                //在这里应当先等待下载线程将图片下载完毕
                try {
                    download.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                
                
                if(!isFinish){
                    throw new RuntimeException("图片没有下载完毕!");
                }
                System.out.println("show:图片显示完毕!");
            }
        };
        download.start();
        show.start();
View Code

static void yield()  暂停当前正在执行的线程对象,并执行其他线程。

3. 线程优先级 

线程优先级一共有10个等级,分别用数字1-10表示 其中1为最低优先级,10为最高优先级,5为默认值.

理论上线程优先级越高的线程获取CPU时间片的次数越多.实际开发中,将某些执行很重要任务的线程

往往设置的优先级会比较高.

        thread1.setPriority(Thread.MAX_PRIORITY);//设置最高优先级
        thread2.setPriority(Thread.MIN_PRIORITY);//设置最低优先级

 

 

4. 守护线程

 

 

 

多线程并发安全

 

当多个线程并发操作同一数据时,由于线程切换时机不可控,会导致线程执行逻辑顺序出现混乱,

导致对数据操作未按照程序设计顺序执行而出现逻辑错误,严重时可能导致系统瘫痪.

class MySingleton { 
 //单例模式(在任何情况下,单例类永远只有一个实例存在)
      
 private static MySingleton instance = null;  
      
    private MySingleton(){}  
      
    public static MySingleton getInstance() {  
        if(instance == null){//懒汉式  
            instance = new MySingleton();  
        }  
        return instance;  
    }  
}



public class MyThread extends Thread{  
      
    public void run() {   
        System.out.println(MySingleton.getInstance().hashCode());  
    }  
      
    public static void main(String[] args) {   
          
        MyThread[] mts = new MyThread[10];  
        for(int i = 0 ; i < mts.length ; i++){  
            mts[i] = new MyThread();  
        }  
          
        for (int j = 0; j < mts.length; j++) {  
            mts[j].start();  
        }  
    }  
}  

上面程序创建了多个线程,分别输出单例对象的hashcode,输出结果为所有单例对象的hashcode值都一样。

因此在多线程并发下这样的实现是无法保证实例实例唯一的,甚至可以说这样的失效是完全错误的。

要保证线程安全,我们就得需要使用同步锁机制  (synchronized关键字)

出现非线程安全问题,是由于多个线程可以同时进入getInstance()方法,那么只需要对该方法进行synchronized的锁同步即可:

public class MySingleton {  
      
    private static MySingleton instance = null;  
      
    private MySingleton(){} 
 
      //静态方法若使用synchronized修饰后,那么该方法一定具有同步效果.
    public synchronized static MySingleton getInstance() {  
        try {   
            if(instance != null){//懒汉式   
                  
            }else{  
                //创建实例之前可能会有一些准备性的耗时工作   
                Thread.sleep(300);  
                instance = new MySingleton();  
            }  
        } catch (InterruptedException e) {   
            e.printStackTrace();  
        }  
        return instance;  
    }  
}  

从执行结果上来看,问题已经解决了,但是这种实现方式的运行效率会很低。

有效的缩小同步范围可以在保证并发安全的前提下提高并发效率。

使用同步块可以更精准的控制需要同步的代码片段:
 synchronized(同步监视器对象){
 需要同步运行的代码片段...
 }

public class MySingleton {  
      
    private static MySingleton instance = null;  
      
    private MySingleton(){}  
      
    //public synchronized static MySingleton getInstance() {  
    public static MySingleton getInstance() {  
        try {   
            synchronized (MySingleton.class) {  
                if(instance != null){//懒汉式   
                      
                }else{  
                    //创建实例之前可能会有一些准备性的耗时工作   
                    Thread.sleep(300);  
                    instance = new MySingleton();  
                }  
            }  
        } catch (InterruptedException e) {   
            e.printStackTrace();  
        }  
        return instance;  
    }  
}  

 同步监视器对象可以是任何的java对象。

静态方法若使用synchronized修饰后,那么该方法一定具有同步效果.

 

public class Thread_syncDemo3 {
    public static void main(String[] args) {
        Thread t1 = new Thread(){
            public void run(){
                Foo.dosome();
            }
        };
        Thread t2 = new Thread(){
            public void run(){
                Foo.dosome();
            }
        };
        t1.start();
        t2.start();
    }
}

class Foo{
    public synchronized static void dosome(){
        try {
            Thread t = Thread.currentThread();
            System.out.println(t.getName()+":正在执行dosome方法...");
            Thread.sleep(5000);
            System.out.println(t.getName()+":执行dosome方法完毕");
        } catch (Exception e) {
        }
    } 
}
View Code

 

 

线程池

 

  阿里云服务器低至 1折86元/年

 

 

 

posted @ 2018-03-06 17:07  沁园Yann  阅读(123)  评论(0编辑  收藏  举报