前言
java高并发第二篇讲的是java线程的基础
依旧不多说废话
线程和进程
进程是操作系统运行的基础,是一个程序运行的实体,windows上打开任务管理器就能看到进程
线程是轻量级的进程,是程序执行的最小单位,是在进程这个容器下进行的
线程基本操作
新建一个线程类有两种方式:
extends Thread
implement 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定义的对象的值是不可变的
今天就先到这里,大家可以看看这些内容的拓展
记得点关注看更新,谢谢阅读
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。