CoreJava学习10——多线程

多线程java

Java的特色之一就是线程的处理较为简单。安全

通常操做系统都支持同时运行多个任务,一个任务一般就是一个程序,每一个运行中的程序被称为一个进程,每一个顺序执行流就是一个线程。多线程

进程:正在运行的程序,是程序动态的执行过程(运行内存中)。并发

线程:在进程内部,并发运行的过程。对于一个程序而言,可能同时运行多个任务,那么每一个任务称为一个线程。app

并发:进程是并发运行的,OS将时间划分为不少时间片断(时间片),尽量均匀分配给正在运行的程序,微观上进程走走停停,宏观上都在运行,这种都运行的现象叫并发,可是不是绝对意义上的“同时发生”。异步


一、Thread类ide

Thread类表明线程类型。函数

咱们调用start()方法时候,该线程会想线程调度注册当前线程。只有注册了,才有机会被分配时间片进行并发运行。高并发

不能调用run方法,若是调用了,就不是并发运行了,就变成同步了。有前后顺序执行。ui


时间片是不均匀的,每一个线程分配时间不是相等的。线程调度机制尽量均匀的将时间片断分配给不一样线程,让他们都有机会的到cpu的运行。分配给谁的时间片断是不可控的。

stop()方法,关闭线程,因为具备不安全性,不建议使用。

正常的线程中止方法是让run()方法正常的执行完毕。

线程运行过程当中,若出现该类未捕获异常,该线程马上终止。可是不会影响当前进程中其余线程的工做。

若当前进程中全部线程都终止了,那么进程终止。


建立线程的另外一种方式将线程与线程体分开,做为线程体就是线程要并发执行的逻辑。最好的模式应该是线程只关心并发操做,不关心具体并发作的事情,咱们应该将线程与线程体自己解耦。


例子:

public static void main(String[] args) {
    /**
    * Thread 类
    * Thread类的一个实例表明一个线程
    * 咱们能够经过继承Thread并重写run方法,来完成咱们想并发的代码。
    */
    Thread thread1 = new NumThread();
    Thread thread2 = new HelloWordThread();
    /**
    * 不能调用run方法,
    */
    thread1.start();
    thread2.start();
}
/**
* 建立一个并发任务
* 重写run方法来编写并发任务代码。
*/
public static class NumThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
        System.out.println(i);
    }
}



二、Runnable实现线程

建立一个实现Runnable接口,重写run方法,以实现了Runnable接口的类的实例对象做为建立Thread类对象的构造函数的参数。

public static void main(String[] args) {
    //建立要并发执行的逻辑再交给线程去
    Thread th = new Thread(new HooThread());
    th.start();
}
public static class HooThread implements Runnable{
    public void run(){
        for (int i = 0; i < 10000; i++) {
            System.out.println("how are you");
        }
    }
}

可是这里经常使用内部类。

new Thread(new Runnable(){

   public void run(){...}

}).start();


这种方式将线程体和线程分离开,咱们就能够最大程度的利用线程,有了这个思想,就有了后面的线程池的应用。


三、线程的生命周期

线程一旦结束,不能再次调用start()方法。、

相关方法:

static void yield()当前现横让出处理器(离开Running状态),使当前线程进入Runnable状态等待,等待下次分配时间片。

static void sleep(times)让线程从Running状态进入block状态,阻塞times好秒后自动回到Runnable状态。

若是在block时,其余线程打断当前线程的Block(sleep)就会发生异常InterruptedException.

void interrupt()中断线程。

final void setPriority(int)改变线程的优先级。

final void join()等待该线程终止。

/**
* 电子表功能
* 思路:
* 1.获取系统时间
* 2.每秒输出一次
*/
SimpleDateFormat format=new SimpleDateFormat("hh:mm:ss");
while(true){
    Date date = new Date();
    String s = format.format(date);
    System.out.println(s);
    Thread.sleep(1000);
}


一个例子:模拟一个节目的砸墙

public static void main(String[] args) {
    /**
    * 砸墙
    * t1线程:林永健 处理睡眠阻塞的线程
    * t2线程:黄宏 用于打断t1睡眠阻塞的线程
    */
    final Thread lin = new Thread(){
        public void run() {
            System.out.println("林:睡觉去了");
            try {
                Thread.sleep(10000000);
            } catch (InterruptedException e) {
                //e.printStackTrace();
                System.out.println("林:干吗呢?都破了相了!");
            }
        }
    };
    lin.start();
    Thread hang = new Thread(){
        public void run() {
            System.out.println("黄:准备砸墙!");
            for (int i = 9; i >0; i--) {
                System.out.println("黄:"+(10*i));
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("黄:搞定!");
            /**
            * 打断t1的睡眠阻塞
            */
            lin.interrupt();//中断线程
        }
    };
    hang.start();
}


四、线程的优先级

线程的优先级根据数字划分为10个等级。

   1最小 对应的常量是 MIN_PRIORIITY

   10最大 对应的常量是 MAX_PRIORIITY

   默认是5 对应的常量是 NORM_PRIORIITY

   //设置优先级

   t1.setPriority(Thread.MAX_PRIORITY);

   t2.setPriority(1);

不是绝对的,但大多状况是这样,毕竟线程分配调度的时间片不可控。


五、守护线程

又叫后台线程,特色:当进程中全部前台线程都终止后,守护线程强制终止。

当进程中只有守护线程时,Java虚拟机退出,进程也终止了。

后台线程是在线程启动前经过方法设置的。

setDaemo(boolean) 当参数是true时,该线程是后台线程。必须在线程启动以前设置,不然没有用了。

//守护线程,要在start以前设置。

jack.setDaemon(true);


六、线程同步的概念

线程同步,能够理解为线程A和B是一块配合,A执行到必定程度时要依靠B的某个结果,因而停下来,示意B执行;B依言执行,在将结果给A;A再继续操做。

所谓同步,就是在发出一个功能调用时,在没有获得结果以前,该调用就不返回,同时其它线程也不能调用这个方法。

   1)异步 并发,各干本身的。

   2)同步 步调一致的处理,多个线程不能同时访问。


这里就引起出一个关键字 Synchronized

多线程并发读写同一个临界资源时发生“线程并发安全问题”

可使用同步代码快解决线程并发安全问题。

synchronized(同步监视器){}


能够修饰一个方法也能够以独立的代码快存在。


同步监视器:是一个任意对象实例,是一个多个线程之间的互斥的锁机制,多个线程要使用同一个“监视器”对象实现同步互斥。

常见的写法:synchronized(this){} 尽可能减小同步范围,提升并发效率。


synchronized修饰的方法,当一个线程进入到该方法后,会对当前方法所属的对象枷锁。其它线程在访问这个方法时候,发现被锁上了,就在方法外等待,直到对象上的锁被释放为止。


七、线程安全类与线程不安全类

   StringBuffer是同步的 synchronized append();

   StringBuilder不是同步的 append();

   Vector/HashTable是同步的。

   ArrayList/HashMap不是同步的。

   若是把一个不是同不的集合变成同步的集,可使用

   Collections.synchronizedList();

   Collections.synchronizedMap();

具体例子以下:

ArrayList list = new ArrayList();

List syncList = Collections.synchronizedList(list);

这样就获得线程安全的集合


也能够直接用

Collections.synchronizedList();

Collections.synchronizedMap();

Collections.synchronizedSet();


获得线程安全的集合。


八、wait和notify简介

属于Object中的方法,用于多线程之间须要协同工做(等待和唤醒)。

就是说:若是条件不知足时,则等待。当条件知足时,等待该条件的线程将被唤醒。在Java中,这个本身的实现依赖于wait/notify.等待机制与锁的机制是密切关联的。

当线程A调用了B对象的wait方法,那么该线程就在B对象上等待。A线程就进入了wait阻塞。若是线程C也调用了B的wait方法,那么该线程也在B对象上等待。当B调用了notify方法,那个A或者B随机一个进入了Runnable状态开始运行,另外一个任然处于wait阻塞。

notifyAll()方法可让等待的全部线程进入Runnable。

相关文章
相关标签/搜索