实现多线程的两种方式
方式一:继承Thread类
1.具体步骤
1.1:创建一个继承Thread类的子类
public class ThreadChild extends Thread {
}
1.2:重写Thread类中的run()方法,将目标操作放在run()方法中
public class ThreadChild extends Thread{
@Override
public void run() {
//目标操作的代码
}
}
1.3:创建子类的对象
ThreadChild tc1 = new ThreadChild();
ThreadChild tc2 = new ThreadChild();
ThreadChild tc2 = new ThreadChild();
1.4:子类对象调用start()方法
tc1.start();
tc2.start();
tc3.start();
方式二:实现Runnable接口
1.具体步骤
1.1:创建一个实现Runnable()接口的实现类
public class ThreadTest implements Runnable {
}
1.2:重写run()方法,将目标操作放在run()方法中
public class ThreadTest implements Runnable {
@Override
public void run() {
//目标操作代码
}
}
1.3:创建实现类对象
ThreadTest tt = new ThreadTest();
1.4:将实现类对象作为参数传递到Thread()构造器中,创建Thread类对象
Thread t1 = new Thread(tt);
Thread t2 = new Thread(tt);
Thread t2 = new Thread(tt);
1.5:Thread类对象调用start()方法
t1.start();
t2.start();
t3.start();
推荐使用实现Runnable()接口的方式实现多线程
---------------------------------------------------------------------------
解决线程安全问题synchronized
什么是线程安全问题?
多个线程共享同一资源,导致共享资源更新不及时
方法一:同步代码块
synchronized(同步监视器){
//需要被同步的代码 ----> 和共享数据有关的操作都需要被同步
}
注:需要被同步的代码要全部写入到同步代码块中,不可将其余代码写入,也不可缺少有关代码
同步监视器
又称为同步锁,具有唯一性,多个线程抢同步锁,哪个线程抢到锁就执行同步代码,其余线程等待锁被释放
哪些可以成为同步监视器?
1.任一类的对象
2.this
3.Sring字符串
4.当前类.class
1.同步代码块+实现Runnable()接口
public class ThreadTest implements Runnable {
@Override
public void run() {
//其他执行操作
//...
synchronized(同步监视器){
//需要被同步的代码 ----> 和共享数据有关的操作都需要被同步
}
//...
}
}
2.同步代码块+继承Thread类
public class ThreadChild extends Thread{
@Override
public void run() {
//其他执行操作
//...
synchronized(同步监视器){
//需要被同步的代码 ----> 和共享数据有关的操作都需要被同步
}
//...
}
}
}
通过继承Thread类的方式实现多线程,创建了多个Thread类的对象,如果此时的同步监视器采用任一类的对象,要保证对象唯一,可以用static修饰;this做同步监视器也违反了唯一性。使用当前类类名.class就可以完美解决问题
synchronized(ThreadChild.class){
//需要被同步的代码 ----> 和共享数据有关的操作都需要被同步
}
方法二:同步方法
将需要被同步的代码放在一个方法中,使用synchronized定义方法
同步方法仍然涉及到同步监视器,只是不需要显式的声明
非静态同步方法默认的同步监视器是:this
静态同步方法默认的同步监视器是:当前类的类类对象 —> 当前类.class
权限修饰符 synchronized 返回类型 方法名(){
//需要被同步的代码 ----> 和共享数据有关的操作都需要被同步
}
1.同步方法+实现Runnable()接口
public class ThreadTest implements Runnable {
@Override
public void run() {
方法名();
}
权限修饰符 synchronized 返回类型 方法名(){ //同步监视器:this(当前对象)
//需要被同步的代码 ----> 和共享数据有关的操作都需要被同步
}
}
2.同步方法+继承Thread类
public class ThreadChild extends Thread{
@Override
public void run() {
方法名();
}
权限修饰符 synchronized 返回类型 方法名(){
//需要被同步的代码 ----> 和共享数据有关的操作都需要被同步
}
}
此时同步方法使用的锁对象默认是this,而继承Thread类实现多线程创建了多个当前对象,此时的锁对象不唯一,因此照旧会出现线程安全问题。
解决方法:将同步方法添加static修饰。注:此时方法体中如果含有调用其他方法,只能调用静态方法
权限修饰符 static synchronized 返回类型 方法名(){ //同步监视器:当前类.class ThreadChild.class
//需要被同步的代码 ----> 和共享数据有关的操作都需要被同步
}