一、两种实现方式: 继承Thread类 和 实现Runnable接口
public class Hello implements Runnable { public void run() { //线程要执行的代码 } public static void main(String[] args) { Hello hello = new Hello(); //实例化一个类的对象 Thread thread1 = new Thread(hello); //new一个线程 Thread thread2 = new Thread(hello); //new一个线程 thread1.start(); //启动线程 } }
也可以这么写:new Thread(对象,线程名);
public class Hello implements Runnable { public void run() { //线程要执行的代码 } public static void main(String[] args) { Hello hello = new Hello(); //实例化一个类的对象 new Thread(hello,"Thread1").start(); new Thread(hello,"Thread2").start(); } }
实际操作中通常采用实现Runnable接口的方法。它有以下的优点:
1 适合多个相同的程序代码的线程去处理同一个资源。
2 可以避免Java的单继承限制。
3 增强程序的健壮性,代码可以被多个线程共享,代码和数据duli。
三、线程的优先级:
线程的优先级用1-10的整数表示。数字越大,优先级越高(10最高)。
默认的优先级为5。
并不是说线程的优先级越高,它就越先执行。只是获得CPU资源的可能性更大些,所以更可能先执行。
在一个线程中开启另外一个线程,则新开线程为该线程的子线程,子线程的初始化优先级与父线程相同。
可以用setPriority()来设置线程的优先级,getPriority()取得线程的优先级。
四、线程的同步和死锁:
同步:在某一时间段里只能有一个线程运行,必须等这个线程结束后,其他线程才能运行。使用同步代码块解决。同步对象一般为this。
synchronized(同步对象){ //需要同步的代码 }
例如售票的例子,若没有解决同步问题,可能在某一时刻,A(线程1)先抢到了卖票系统的CPU资源,正在买但还没买完。这时B(线程2)抢到了CPU的资源,它开始了买的动作,这样就会出错。
合理安全的情况应该是这样的:假如A先抢到了卖票系统的资源,则他开始买票,直到他买票的行为结束后,才可以释放系统的资源,允许其他人买。
public class Sell implements Runnable { private int count = 5; public static void main(String[] args) { Sell hello = new Sell(); //实例化一个类的对象 new Thread(hello,"A").start(); new Thread(hello,"B").start(); } public void run() { for(int i=0;i<10;++i) { synchronized (this) { if(count>0) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(count--); if(count==0) { System.out.print("票已售罄"); } } } } } }
死锁:当两个或者多个线程同时执行时,如果每个线程都占有一个共享的系统资源并还要请求另一个对方正在使用的共享资源,这时就会出现死锁的可能性。也就是两个对象都在调用对方的同步代码,都在等待对方释放同步锁,这时便会成为僵持状态。这就是死锁。在多线程开发中应该尽可能避免死锁的出现。
能出现死锁的代码是不安全的多线程代码。
安全的多线程代码:
1.变量为局部变量。因为其完整生命周期都处在一个线程内。