1、创建分线程的方式
2、单例模式懒汉式线程安全问题
3、java线程同步
4、java线程通信
5、java的内存模型
认识线程:
每一个java程序都有一个隐含的主线程,即main()方法。
程序–>进程 —>线程 理解
何时需要多线程操作:
1,程序需要执行多个任务的时候。
2,程序需要实现一个等待的任务时,如等待用户输入,文件读写,网络操作,搜索等。
3,程序需要后台运行的程序时。
创建分线程的方式:
1,继承Thread类,其子类重写Thread类的run()方法即可。
每一个线程都是通过Thread类的run()方法来完成相应的功能,经常把run()方法的主体称为 线程体。
通过子类对象的start()方法来执行当前线程。start()方法的两个作用:①启动当前线程 ②执行线程的run()方法。
2,创建实现Runnable接口的类,并且实现接口中的抽象run()方法。
实例化一个Rundnable接口实现类的对象,并将此对象作为参数传递给Thread类的构造器。
通过Thread类对象调用strar()方法执行当前线程。
多线程认识:JVM负责管理这些线程,这些线程将被轮流执行。使得每一个线程都有机会使用CPU资源。
两种分线程创建的联系和区别:
1,public static Thread implements Runnable
{Thread 类的本质如上实现了Runnable 接口}
2,第二种分线程创建的方式如下优点:
①没有单继承的局限
②若多线程有共享数据的话,实现更加方便。
使用Thread子类创建线程的优点:
可以在子类中增加新的成员变量,使得线程具有某种属性,也可以在子类中新增加方法,使线程具有某种功能。但是java不支持多继承,Thread类的子类不能再拓展其他类。
* 1.start():开启线程;执行相应的run()
* 2.run():分线程要执行的功能封装在run()中
* 3.currentThread():获取当前正在执行的线程
* 4.getName():获取当前线程的名字
* 5.setName():设置当前线程的名字
* 6.yield():暂时释放线程对当前cpu的占用
* 7.join():在线程a中调用线程b.join()表示:当前线程a进入阻塞状态,线程b开始执行,直到线程b执行结束,线程a才继续执行。
* 8.sleep(long millitimes):显示的使得当前线程睡眠指定的毫秒数。这个过程中,当前线程处于阻塞状态
* 9.isAlive():当前线程是否还存活
*
* 10.线程的优先级:getPriority() / setPriority(int i)
* MIN_PRIORITY:1
* NORM_PRIORITY:5
* MAX_PRIORITY:10
* 优先级高,并不是当前线程被首先执行完,而是被执行的概率大
* 11.线程的通信: wait() / notify() / notifyAll()
单例模式-懒汉式线程安全及高效率的问题
public Bank getInstance() {
if (bank == null) {
synchronized (this) {
if (bank == null) {
bank = new Bank();
}
}
}
return bank;
}
线程的生命周期:
线程的同步机制:解决线程的安全问题
出现线程安全问题的原因:
当一个线程在操作共享数据的过程中,还没有执行结束,另外的线程就参与进来,同样的去操作共享数据,就导致了出现了线程安全的问题
如何解决:
必须让一个线程完整的操作完共享数据之后,其他的线程才可以参与进来,继续操作共享数据。
java同步机制
同步代码块:
synchronized(同步监视器){
//需要被同步的代码
}
同步方法:
public synchronized void show(){
//方法体
}
除了synchronized关键字之外,还可以定义一个可重入锁的变量
private ReentrantLock lock = new ReentrantLock();
lock.clock()
try{
//需要被同步的代码块
}finally{
lock.unlock()}
从Java 5开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。 Lock是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。 在实现线程安全的控制中,比较常用的是ReentrantLock(可重入锁),可以显式加锁、释放锁。
说明:
1.需要被同步的代码,即为操作共享数据的代码
2.共享数据:多个线程共同操作的变量。
3.同步监视器,俗称锁。哪个线程获取了锁,哪个线程就执行大括号中需要被执行的代码。其它的线程在外面等待。
共享数据的访问权限必须是private,以保证当前线程访问数据的时候,工作主内存空间的线程不能访问和操作数据。
>任何一个类的对象都能充当锁
>保证线程的安全,需要所有的线程共用同一把锁!,(优先考虑this)
释放锁的操作:
1、当前线程的同步方法、同步代码块执行结束
2、当前线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行。
3、当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束
4、当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。
不会释放锁的操作:
1、线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行。
2、线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。
应尽量避免使用suspend()和resume()来控制线程
线程通信
wait():一旦执行到此方法,就使得当前线程进入阻塞状态。直到其他线程唤醒为止。
notify():一旦执行到此方法,就会唤醒其它被wait()的线程中优先级最高的一个。
notifyAll():一旦执行到此方法,就会唤醒其它所有被wait()的线程
要求:
1.如上的三个方法必须使用在同步方法或者同步代码块中。
2.如上的三个方法的调用者必须是同步方法或者同步代码块的同步监视器!
Java.lang.Object提供的这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报如下异常:
java.lang.IllegalMonitorStateException
在当前线程中调用方法:对象.wait()/wait() 功能,使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify (或notifyAll) 为止。
调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁) 调用此方法后,当前线程将释放对象监控权 ,然后进入等待 在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。
在当前线程中调用方法:对象名.notify() 功能,唤醒等待该对象监控权的一个线程。
调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁