一、线程两种创建方式:
1.继承Thread类创建线程:
public class FirstThreadTest extends Thread {
public void run(){
System.out.println("这里是线程的执行方法");
}
public static void main(String[] args) {
//获得线程
FirstThreadTest thread = new FirstThreadTest();
System.out.println("线程名称为:"+thread.getName());
//启动线程
thread.start();
System.out.println("main方法也是一个线程:"+Thread.currentThread().getName());
}
}
2.实现Runnable接口创建线程:
- (1)定义runnable接口的实现类,并重写该接口的run()方法,该run()方法的方法体同样是该线程的线程执行体;
- (2)创建 Runnable实现类的实例,并依此实例作为Thread的target来创建Thread对象,该Thread对象才是真正的线程对象;
- (3)调用线程对象的start()方法来启动该线程。
public class RunnableThreadTest implements Runnable {
public void run() {
System.out.println("这里是线程方法");
System.out.println("线程名为:" + Thread.currentThread().getName());
}
public static void main(String[] args) {
System.out.println("main方法线程:" + Thread.currentThread().getName());
RunnableThreadTest rtt = new RunnableThreadTest();
new Thread(rtt, "新线程1").start();
new Thread(rtt, "新线程2").start();
}
}
二、多线程并发的主要引发的两个问题:
1.多线程共享数据同步问题:synchronized
<1>多个线程共享同一个数据时,那面会出现抢占,错拿等问题。。
<2>线程安全问题:
- 两个同时从一个箱子里面拿苹果,两个人就是两个线程,箱子里的苹果是他们共享的数据;当两个人同时把手放到箱子里面时就会发生线程安全的问题,如:两个人拿到同一个苹果 发生互不想让的情况;
- 比如共20个苹果,当A刚好把苹果拿到手上,总数还没有进行减一操作时,B就来了 所以它认为的苹果总数还是20 但是实际已经是19了,就会线程不安全;
<3>线程安全解决:synchronized关键字(对象锁---尽量锁在范围小的地方,提高效率);
synchronized:当用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码;
<4> 当run()方法发生异常,而且没有得到解决时,该线程会终止,但不会影响该进程中的其他线程;
2.数据因并发产生不一致问题:ThreadLocal
ThreadLocal:为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象。
<1>ThreadLocal 不是用来解决共享对象的多线程访问问题的,通过ThreadLocal.set()到线程自己的对象,其他线程下能不需要访问,也访问不到,各个线程反复问额对象都是不一样的,因此不用考虑共享对象的问题;
<2>ThreadLocal使得各线程能够保持各自独立的一个对象,并不是通过ThreadLocal.set()来实现的,而是通过每个线程中的new 对象的操作来创建的对象(new 了一个新线程对象,而不是引用一个对象),每个线程创建一个,不是什么对象的拷贝或副本。
ThreadLocal和Synchonized都用于解决多线程并发访问。但是ThreadLocal与synchronized有本质的区别:
- 1、synchronized关键字主要解决多线程共享数据同步问题,ThreadLocal使用场合主要解决多线程中数据因并发产生不一致问题;
- 2、synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享;
- 3.Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离;
- 4.ThreadLocal本质上不是Thread ,而是线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是Java中一种较为特殊的线程绑定机制,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。
- 5.ThreadLocal维护变量副本:在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。
- 6.概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
- 7.按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用synchronized进行线程同步。但Spring的DAO模板类并未采用线程同步机制,因为线程同步限制了并发访问,会带来很大的性能损失。
- 8.在无需同步的情况下就化解线程安全的难题---ThreadLocal在Spring中发挥着重要的作用,在管理request作用域的Bean、事务管理、任务调度、AOP等模块都出现了它们的身影,起着举足轻重的作用。
参考:https://blog.csdn.net/u012385190/article/details/53302239