前言
java高并发第二篇讲的是java线程的基础
依旧不多说废话线程和进程
进程是操作系统运行的基础,是一个程序运行的实体,windows上打开任务管理器就能看到进程
线程是轻量级的进程,是程序执行的最小单位,是在进程这个容器下进行的线程基本操作
新建一个线程类有两种方式:extends Threadimplement Runnable
推荐使用Runnable接口(这不废话吗)
- 1.创建线程
Thread t1 = new Thread(){ @Ovveride public void run(){ System.out.println("create"); }t1.start();
重构run()方法,用start()启动线程
- 2.终止线程
Thread.stop();
不推荐stop,强行终止不能保证原子性
这里给大家写一个终止线程的推荐方法:public class interruptTest { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(){ public void run(){ while (true){ System.out.println("go"); if (Thread.currentThread().isInterrupted()){ break; } } } }; t1.start(); Thread.sleep(10001); t1.interrupt(); }}
看懂了吗?
方法解释:interrupt和stop不同的是,stop会立即中断线程,而interrupt的中断线程由线程自己决定Thread.interrupt() //设置中断标志Thread.isInterrupted() //判断当前线程是否有中断标志,如果有,返回true
sleep()也能让线程暂时性的中断,即让线程休眠
- 3.线程协作之等待和通知
多线程之间的协作可以使用等待(wait())和通知(notify)进行
wait和notify不能乱用,它们必须包含在synchronzied(即同步)的方法中无论是wait还是notify,都需要一个目标对象的监听器(也叫锁)当线程1在一个同步的object对象中运行的时候,突然执行object.wait()方法,此时线程停止执行,并且退出object对象,释放对象的监听器,线程1进入等待队列
接着线程2进入object对象,首先拿到object对象的监听器,当线程2执行object.notify()方法时,对象object会随机选择一个等待队列中的线程,并将其唤醒,然后线程2释放监听器,那个被唤醒的线程就会进来用图更形象:
- 4.线程协作之结束和谦让
多线程之间的协作可以使用结束(join())和谦让(yield())进行
join()方法就是让一个线程加入到另一个线程,至于怎么个加入法看下面一个例子:public class JoinTest { public volatile static int i=0; public static class JoinThread extends Thread{ @Override public void run(){ for (i=0;i<1000;i++){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) throws InterruptedException { JoinThread joinThread = new JoinThread(); joinThread.start(); System.out.println(i); }}
这个方法打印出来的i
大家肯定知道,一定是0,因为我们在这个类的主线程里执行,虽然joinThread和主线程一起执行了,但是主线程并不会去理会joinThread,只管执行打印代码:
再来看看加入join()后的结果:
现在很容易理解了,因为joinThread线程加入到了主线程中,joinThread的join()让主线程去等待它完成才执行打印,所以会打印出1000
yield()是谦让,字面意思,就是我已经完成一些最重要的事情了,不想再占着CPU资源,需要休息啊一下,但是能否被分配到CPU资源就不一定了
守护线程
守护线程是在后台默默完成系统服务的线程,如垃圾回收线程,JIT线程
与之相应的是用户线程,也就是用户完成业务要用的线程当一个java程序中只剩守护线程的时候,JVm就会自然退出下面用一段代码证明:代码new Thread().setDaemon(true);
就是设置为守护线程 public class DaemonTest { public static class DaemonT extends Thread{ public void run(){ while (true){ System.out.println("我还在"); try { Thread.sleep(100); } catch (InterruptedException e) { } } } } public static void main(String[] args) throws InterruptedException { DaemonT daemonT = new DaemonT(); daemonT.setDaemon(true); daemonT.start(); Thread.sleep(2000); }}
上面代码在主线程运行两秒后,自动关闭应用,因为只有守护线程
线程优先级设置
java的线程优先级可以用1-10表示
数字越高表示优先级越高Thread thread1 = new Thread();thread.setPriority(10);
这样thread1线程的优先级就是最高的
线程安全与synchronized
为了保证线程安全,我们之前讲过可以使用volatile保证变量可见性
但是volatile并不能真正的保证线程的安全 使用synchronized保证线程安全,synchronized会在对象上加锁使同一时间只能有一个线程进入该对象synchronized的用法整理:指定加锁对象:对给定对象加锁,进入同步代码前获得给定对象的锁直接作用于实例方法:相当于对当前实例加锁直接作用于静态(static)方法,相当于给当前类加锁
所以要注意在同个线程指定的监听对象是new Test()
还是test
实例
Tips
HashMap的多线程编程是不安全的,可能导致机子死机,两个线程交互next会进入死循环。可以用ConcurrentHashMap代替
ArrayList可以用Vector代替Integer定义的对象的值是不可变的今天就先到这里,大家可以看看这些内容的拓展
记得点关注看更新,谢谢阅读