Java多线程笔记 多学多练(一)
java多线程学习笔记
写在前言,不管学习什么知识点,自己还是要边学边用。
在学习的过程中把一些自己认为重要的知识点记下来,看书只是为了看明白,吸收为自己的东西还需要自己多练练。然后自己做个总结,隔一段时间翻翻看看,这样长期有效记忆会很深刻。
多线程的书籍有很多,但是通俗易懂,结构层次清晰的我还是推荐一本书《java多线程编程核心技术》。
好了,言归正传。我们来一起学习多线程吧。
1、 进程和线程的概念
什么是进程呢?
进程就是一个程序运行中所占用一定的资源,进程是程序的实体。
什么又是线程呢?
线程就是进程里独立运行的子程序,比如音乐播放器边播放音乐,边去下载音乐。这就是2个子程序同时进行的。、
那用多线程有什么好处吗?
使用多线程,可以充分利用CPU资源。现在多核CPU很常见,一个程序的多个线程在不同时间在CPU不同核中进行处理,而不用等一个任务执行完后再执行下一个任务,这样效率太低了。但是多个线程在不同核中不停地切换,就需要消耗一定的时间资源。
2、如何使用多线程
java使用多线程有两种方法:
1)继承Thread类
其实,Thread类也是实现了Runnabled的接口
public class Thread implements Runnable {}
public class ThreadDemo extends Thread{}
2)实现Runnabled接口
public class ThreadDemo implements Runnable {
@Override
public void run() {
}
}
我们来看看下面的一段代码:
public class ThreadDemo extends Thread {
private int i = 0;
@Override
public void run() {
i++;
System.out.println("i:" + i);
}
public static void main(String[] args0) {
ThreadDemo threadDemo = new ThreadDemo();
Thread t = new Thread(threadDemo);
Thread t2 = new Thread(threadDemo);
Thread t3 = new Thread(threadDemo);
Thread t4 = new Thread(threadDemo);
Thread t5 = new Thread(threadDemo);
t.start();
t2.start();
t3.start();
t4.start();
t5.start();
//System.out.println("run over.");
}
}
结果是:
可以看出线程是乱序执行的,如果想让它按照顺序执行,这样的程序是线程不安全的。也就是数据共享,没有原子性。其他线程容易篡改变量的值,造成了脏读、幻读的影响,将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完成操作之前,被其他线程的调用, 从而保证了该变量的唯一性和准确性就使用 synchronized关键字。
这个synchronized就把run()方法锁定了,每次只能进去一个线程,去修改它的值。其他线程在抢着这把锁的key,等到前面一个线程执行完run()方法内的程序后,下一个随机线程获取了key再去执行run()方法。
3、 currentThread()方法是获取当前线程
可以看出t.run()和t.start()当前线程不一致。这是因为t.start()方法是被Thread类的线程Thread-1调用的,而run方法是main方法里直接调用的,所以是main线程。
4、isAlive()
线程是否存活。
5、sleep()方法
让真正执行的线程休眠(暂停执行)。
@Override
public void run() {
try {
System.out.println("begin...");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("run:"+this.isAlive());
}
打印begin...两秒后,打印后面的run:true。
6、getId()方法
获取线程ID。
7、停止线程
停止线程很重要,一般来说有stop()强制停止线程。但因为太暴力,会让一个正在运行的线程突然终止,数据得不到同步处理,对象突然被解锁,后果很严重。
我们可以采用interrupt方法来终止线程。interrupt方法只是给这个线程标识为“要终止”的状态,而并不是调用就立即生效。
我们可以采用在run方法中判断是否是interrupt状态来抛出异常终止线程,或者return返回来终止线程。
public class ThreadDemo3 extends Thread {
@Override
/*public void run() {
super.run();
try {
for (int i = 0; i < 10000; i++) {
//如果线程状态为终止
if (this.isInterrupted()) {
System.out.println("我要停止了...");
//抛出异常
throw new InterruptedException();
}
System.out.println("i:" + i);
}
System.out.println("for循环外代码块..");
} catch (InterruptedException e) {
e.printStackTrace();
}
}*/
public void run() {
while (true) {
for (int i = 0; i < 10000; i++) {
if (this.isInterrupted()) {
System.out.println("我要停止了...");
// 返回结束线程
return;
}
System.out.println("i:" + i);
}
System.out.println("for循环外代码块..");
}
}
public static void main(String[] args0) {
try {
ThreadDemo3 threadDemo = new ThreadDemo3();
threadDemo.start();
Thread.sleep(100);
threadDemo.interrupt();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
两种方法终止线程 ,终止后for循环外的代码是不会执行的,直接结束了。
8、暂停线程
thread. suspend();暂停线程
thread.resume();恢复线程
缺点是容易造成公共的同步对象独占,使其他线程访问不到公共同步对象。也就是缺点:不同步。
9、yieId方法
放弃当前CPU的资源,让给其他任务占用CPU。但放弃的时间不确定,可能刚刚放弃,又被占用了。
Thread.yieId();
10、线程优先级
线程的优先级越高,得到的CPU资源越多。一共分为1-10等级。如果超越这个范围就会报IllegalArgumentException()异常。
线程的优先级具有继承性,也就是说子线程继承父线程优先级。默认是5。
Thread.currentThread().getPriority();//获取线程优先级
Thread.currentThread().setPriority(10);//设置线程优先级
优先级高的线程并不一定先执行完,具有随机性。
11、守护线程
守护线程是陪伴另一个线程,当进程中不存在非守护线程时,守护线程会自动销毁。GC(垃圾回收器)就是一个守护线程。
上一篇: Redmi红米路由器怎么恢复出厂设置? 路由器恢复出厂的技巧
下一篇: 有线头