JavaSE多线程总结
1.进程与线程的定义
进程:一个应用程序。
线程:一个应用程序的执行场景或是执行单元
举例:
进程1:阿里巴巴
线程A: 马老师
线程B: 前台小姐姐
进程2:京东
线程A: 刘老师
线程B: 前台小姐姐
进程1和进程2是独立不共享的
线程1和线程2堆内存和方法区共享;栈空间独立不共享
2.实现线程的方法
- 编写一个类,直接继承Thread,重写run方法:
//定义线程类
class MyThread extends Thread{
@Override
public void run(){}
}
//创建线程对象
MyThread m = new MyThread;
//启动线程
m.start();
- `编写一个类,实现Runnable接口,重写run方法:
//定义一个可运行的类
class MyThread implements Runnable{
@Override
public void run(){}
}
//创建线程对象
Thread t = new MyThread(new Runnable);
//启动线程
t.start();
- 采用匿名内部类:
Thread t = new Thread(new Runnable(){
@Override
public void run(){}
});
//启动线程
t.start();
3.线程的生命周期
注意:锁池不算生命周期中的状态。线程生命周期五大状态:开始,就绪状态,运行状态,阻塞状态,结束。
4.获取线程的名字
currentThread()方法:
public static void main(String args[]){
Thread currentThread = Thread.currentThread();
//获取当前线程的名字
System.out.println(currentThread.getName());
//创建线程类对象
MyThread2 m2 = new MyThread2();
//修改线程对象的名字
m2.setName("T1");
//获取线程对象的名字 默认名字为Thread-0
String s = m2.getName();
System.out.println(s);
}
class MyThread2 extends Thread{
@Override
public void run(){
for(int i=0; i<100; i++){
//currentThread就是当前线程对象
Thread currentThread = Thread.currentThread();
System.out.println(currentThread.getName()+" "+i);
}
}
}
5.线程安全
未来的开发中,我们的项目是运行在服务器上的,服务器已经将线程定义并穿创建了,我们需要做的就是确保我们的代码 数据是否是安全的?
5.1 线程安全问题出现的条件:
①多线程并发
②有共享资源
③共享资源有修改的行为
5.2如何解决线程安全问题:
存在线程安全问题时:需要执行线程排队处理(多个线程不能并发),也称之为 “线程同步机制”。
5.3同步/异步机制:
异步编程模型:线程A和线程B,各自执行各自的,A不管B,B不管A,谁也不需要谁(多个线程并发,效率高,安全低)
同步编程模型:线程A和线程B,当线程A执行时,线程B必须排队等候线程A执行完毕后再进行操作;(多个线程排队执行,效率低,安全高)
5.4synchronized三种写法:
①同步代码块
synchronized (线程共享对象){
同步代码块;
}
②在实例方法上使用synchronized
表示共享对象一定this
并且同步代码块是整个方法体
③在静态方法上使用synchronized
表示找类锁
类锁永远只有一把
就算创建了100个对象,类锁也只有一把
5.5实际开发中如何解决线程安全问题:
synchronized会让程序的执行效率降低,用户体验极差
①尽量使用局部变量代替 “实例变量和静态变量”
②如果必须是实例变量,那么可以考虑创建多个对象,这样实例变量的内存就不共享了(1个线程对应1个对象,100个线程对应100个对象,
对象不共享,就没有数据安全问题了)
③如果不能使用局部变量,对象也不能创建多个,这个时候就只能选择synchronized,线程同步机制
5.6线程其他内容:
①守护线程 .setDaemon()
java中线程分为两大类:
一种是用户线程:main属于用户线程
一种是守护线程(后台线程):垃圾回收机制
守护线程的特点:
一般守护线程是死循环,所有的用户线程只要结束,守护线程就会自动结束
②定时器
③ 实现线程的第三种方式 Future方式,实现Callable接口(JDK8新特性)
这种方式可以获得返回值
④关于Object的wait和notify方法(生产者消费者模式)
wait方法和notify方法不是线程对象的方法,是java中任何一个java对象都有的方法
wait方法作用:
Object o = new Object;
o.wait();
让正在o对象上活动的线程进入等待状态,无期限等待,知道被唤醒,o.wait()会让 “当前线程”进入等待状态
o.notify()唤醒正在o对象等待的线程
o.notifyALL()唤醒正在o对象等待的所有线程
5.7生产者/消费者模式
public class TestThread10 {
public static void main(String[] args) {
//
List list = new ArrayList();
Thread t1 = new Thread(new Producer(list));
Thread t2 = new Thread(new Consumer(list));
t1.setName("生产者线程");
t2.setName("消费者线程");
t1.start();
t2.start();
}
}
//生产线程
class Producer implements Runnable{
//仓库
private List list;
public Producer(List list){
this.list = list;
}
@Override
public void run() {
//一直生产(死循环模拟一直生产)
while (true){
synchronized (list) {
if (list.size() > 0) {
//当前线程进入等待状态,并释放list集合的锁
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序执行到这里说明仓库是空的,需要生产
Object obj = new Object();
list.add(obj);
System.out.println(Thread.currentThread().getName()+"-->"+obj);
list.notify();
}
}
}
}
//消费线程
class Consumer implements Runnable{
private List list;
public Consumer(List list){
this.list = list;
}
@Override
public void run() {
//一直消费(死循环模拟一直消费)
while (true){
synchronized (list) {
if (list.size() == 0) {
//仓库空了,消费者等待,并且释放list的锁
try {
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序执行到这里说明仓库满了,需要消费
Object obj = list.remove(0);
System.out.println(Thread.currentThread().getName()+"-->"+obj);
list.notify();
}
}
}
}
多线程这一块总结了这么多,把学到的知识梳理了一下,可能还有些没有总结到,希望这些对大家有帮助。另外生产者消费者这一块,我也是看了好久,也希望各位大佬能给出自己的理解供参考~!