目的:因为自定义的run()方法,所属的对象是Runnable接口的子类对象,所以要让线程去指定对象的run()方法,就必须明确该run()方法的所属对象
5、调用Thread类的static方法开启线程并调用run()方法
class RunnableTestDemo implements Runnable{
@Override
public void run() {
System.out.println("实现Runnable接口");
}
}
public class RunnableTest {
public static void main(String[] args) {
RunnableTestDemo r = new RunnableTestDemo();
Thread t1 = new Thread(r);
t1.start();
}
}
实现Runnable接口与继承Thread的区别:
1、接口方法避免了Java单继承的局限性
2、继承Thread,线程代码存放在Thread子类run()方法中
3、实现Runnable接口,线程代码存放在接口紫子类的 run()方法中
所以,在选择实现Runnable接口与继承Thread这两者中,建议使用实现Runnable接口的方式
线程的状态
见上图,可看到线程的状态分为:
1、创建线程(new 线程类),调用start()方法执行run()方法
2、运行状态:具有执行资格,并且有执行权
3、冻结状态:没有执行资格,没有执行权
4、临时状态(阻塞):具有执行资格,没有执行权。等待cpu的执行权
5、消亡状态:线程结束
根据线程的状态的执行原理是:创建一个线程A,调用start()方法,执行run()方法,当线程运行时,遇到sleep(time)或者wait()方法,线程就会进去冻结状态(放弃了执行资格),只有当sleep(time)或者执行了notify()方法,冻结状态就会变成临时状态(阻塞),这时临时状态的线程就会去同其他的线程一起抢夺cpu的执行权,一旦抢到cpu的执行权,该临时状态的线程就会运行(run),变成运行状态run,直到run()方法中的代码执行完,线程才会结束,变成最后的消亡状态。
同步代码块
较多情况下,Java在处理多线程的时候,会出现一些安全问题,而Java处理多线的安全问题的是方式,是使用同步代码块(synchronized(对象/this/类名.class))或者同步代码函数。
但是在解决多线程的安全问题时,使用同步代码块的前提是:
1、必须要有两个或者两个以上的线程
2、必须是多个线程使用同一个锁(如果存在多个类使用到同步,那么在这几个类中找唯一类,也就是找使用到同步快的共同类)
3、必须保证听你同步代码块中只能有一个线程在运行。
同步代码块的好处是解决了线程的安全问题,坏处是多个线程进去同步代码块的时候都要去判断,较为消耗资源。
在使用同步代码块的前提下,得确认线程是否存在安全性问题,如果找到线程的安全性问题;
1、明确哪些代码是多线程运行的代码
2、明确共享数据
3、明确多线程运行代码中哪些语句是操作的共享数据
同步代码块或者同步代码函数的运行原理:
1、将需要解决安全问题的代码放到同步代码块中
2、当多个线程运行时,第一个线程A获得cpu的执行权,首先会来判断真假是否持有锁,如果有,线程A就会进入到同步代码块中,并且进入到里面的第一件时间就是将同步锁给关闭。
3、然后线程A在同步代码块中,执行同步代码块中的代码。
4、在此之前,其他线程即使获得cpu的执行权也无法进入到同步代码块中,因为没有获得锁。
5、当线程A将同步代码块中的代码执行完毕时,最后一步是打开同步锁,然后退出。
6、这时,其他线程就可以获得cpu的执行权后并且获得同步锁,进入到同步代码块中,执行操作。
public class MyThread implements Runnable{
private static int i = 100; //多个线程共享的数据
boolean flag = true;
public void printVal(){
if(flag){
while(true){
synchronized(this){
if(i>0){
System.out.println("-----code"+i--);
}
}
}
}else{
while(true){
printStaticVal();
}
}
}
public static void printStaticVal(){
while(true){
synchronized(MyThread.class){
if(i>0){
System.out.println("-----Static"+i--);
}
}
}
}
public void run(){
printVal();
printStaticVal();
}
}
class TestSync {
public static void main(String[] args) {
TestSync t = new TestSync();
Thread my1 = new Thread(t);
Thread my2 = new Thread(t);
my1.start();
my2.start();
}
}