并发机制,每一个任务(或事件)就是一个线程。
并发机制就是说同事干多个事,比如你呼吸的同时还可以行走说话等,这就是并发机制。
Java具有并发机制,也就是说Java可以同时执行多个线程。
Windows操作系统是多任务操作系统,以进程为单位,在级短的时间内只执行一个线程,然后跳转到另一个线程上执行,由于cpu运行速度太快加上在每个线程上存留的时间极短所以看上去就好像所有的线程都在同步执行一样。
Java中主要提供两种方式实现线程,分别为继承Java.lang.Thread类与实现Java.lang.Runnable接口。
继承Java.lang.Thread类:
Thread类中实例化的对象代表线程,常用的构造方法如下:
public Thread(); 创建一个新的线程对象。
public Thread(String threadName); 创建一个名称为threadName的线程对象。
继承Thread类创建一个新的线程的语法: public class ThreadTest extends Thread{}
完成线程真正功能的代码应该累的run()方法里,当一个类继承了Thread类后,就可以在该类中覆盖run()方法,将实现该线程功能的代码写入run()方法中,然后同时调用Thread类中的start()方法执行线程,也就是调用run()方法。
run()方法的语法格式:
public void run(){}
如果start()方法调用一个已经启动的线程,系统将抛出IllegalThreadStateException异常。
当执行一个线程程序时,就自动产生一个线程,主方法正是在这个线程上运作的。当不再启动其他线程时,该程序就为单线程程序,代码如下:
package thread;
public class ThreadTest01 extends Thread{
private int count = 10;
public void run() {
while(true) {
System.out.println(count);
if(--count == 0){
return;
}
}
}
public static void main(String[] args) {
new ThreadTest01().start(); //如果没有调用start()方法,线程永远都不会启动。Thread对象 //也就只是个对象
}
}
如果需要继承其他类,而且还要使当前类实现多线程,可以通过Runnable接口来实现。语法如下:
public class Thread extends Object implements Runnable
实现Runnable接口的程序会创建一个Thread对象,并将Runnable对象与Thread对象相关联。Thread类中有两个构造方法:
public Thread(Runnable target)
public Thread(Runnable target, String name)
这两个构造方法的参数中都存在Runnable实例,使用以上构造方法就可以将Runnable实例与Thread实例相关联。
使用Runnable接口启动新的线程的步骤如下:
1)建立Runnable对象。
2)使用参数为Runnable对象的构造方法。
3)调用start()方法启动线程。
线程的生命周期
线程具有生命周期,其中包含7种状态,分别是出生状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态和死亡状态。出生状态就是线程被创建的时所处的状态,在用户使用该线程实例调用start()方法之前线程都处于出生状态;当用户调用start()方法后,线程处于就绪状态(又被称为可执行状态);当线程得到系统资源后就进入运行状态。
一旦线程进入可执行状态,他就会在就绪与运行状态下转换,同时也有可能进入等待、休眠、阻塞或死亡状态。当处于运行状态下的线程调用Thread类中的wait()方法时,则会进入休眠状态。进入等待状态的线程必须调用Thread类中的notify()方法才能被唤醒,而notifyAll()方法是将所有处于等待状态下的线程唤醒;当线程调用Thread类中的sleep()方法时,则会进入休眠状态。如果一个线程在运行状态下发出输入/输出请求,该线程将进入阻塞状态,在其等待输入/输出结束时线程进入就绪状态,对于阻塞的线程来说,即使系统资源空闲,线程依然不能回到运行状态。当线程的run()方法执行完毕时,线程进入死亡。
操作线程的方法
线程的休眠
调用sleep()方法,该方法需要参数用于指定该线程休眠的时间,单位是毫秒。
线程的加入
如果当前某程序为多线程程序,假如存在一个线程A,现在需要插入线程B,要求线程B现执行完毕,然后再继续执行线程A,此时可以使用Thread类中的join()方法来完成。这就好比此时读者正在看电视,突然有人上门收水费,读者必须付完水费后才能继续看电视。
当某个线程使用join()方法加入到另外一个线程时,另一个线程会等待该线程执行完毕后再继续执行。
线程的中断
在run()方法中使用无限循环的形式,然后用判断语句在合适的地方使用break语句。
如果线程是因为使用了sleep()或wait()方法进入了就绪状态,可以使用Thread类中interrupt()方法使线程离开run()方法,同时结束线程,但程序会抛出InterruptedException异常,用户可以在处理该异常时完成线程的中断业务处理,如终止while()循环。
代码如下:
package thread;
import javax.swing.JFrame;
import java.awt.BorderLayout;
import javax.swing.*;
public class Interrupted extends JFrame{
Thread thread;
public static void main(String[] args) {
init(new Interrupted(),100,100);
}
public Interrupted() {
super();
final JProgressBar progressBar = new JProgressBar();
getContentPane().add(progressBar, BorderLayout.NORTH);
progressBar.setStringPainted(true);
thread = new Thread(new Runnable() {
int count = 0;
public void run() {
while(true) {
progressBar.setValue(++count);
try {
thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("当前线程被中断!");
break;
}
}
}
});
thread.start();
thread.interrupt();
}
public static void init(JFrame frame, int width, int height) {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(width, height);
frame.setVisible(true);
}
}
线程的优先级
Thread类中包含的成员变量代表了线程的某些优先级。在多任务操作系统中,每个线程都会得到一小段CPU运行时间片运行,在时间结束时,将轮换另一个线程进入运行状态这时,系统会选择与当前线程优先级相同的线程予以运行。系统总选择就绪状态下优先级比较高的线程进入运行状态。
优先级8 线程1 线程2
优先级5 线程3 线程4
优先级3 线程5
如上的优先级别程序线程1先得到时间片,时间到了之后然后线程2,然后线程1.。。。直到线程1和线程2都执行完毕后才会轮到线程3,线程3时间到了轮线程4,然后线程3。。。直到线程3和线程4都执行完了才会运行线程5。
线程同步
多线程程序,会发生两个线程抢占资源在多线程编程中需要防止这些资源访问的冲突。Java提供了线程同步的机制来防止资源访问冲突。
线程安全
线程安全问题来源于两个线程同时存取单一对象的数据。
代码如下:
package thread;
public class ThreadSafeTest implements Runnable {
int num = 10;
public void run() {
while(true) {
if(num > 0) {
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("tickets"+ num--);
}
}
}
public static void main(String[] args) {
ThreadSafeTest t = new ThreadSafeTest();
Thread tA = new Thread(t);
Thread tB = new Thread(t);
Thread tC = new Thread(t);
Thread tD = new Thread(t);
tA.start();
tB.start();
tC.start();
tD.start();
}
}
package thread;
public class ThreadSafeTest implements Runnable {
int num = 10;
public void run() {
while(true) {
synchronized("") {
if(num > 0) {
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("tickets"+ num--);
}
}
}
}
public static void main(String[] args) {
ThreadSafeTest t = new ThreadSafeTest();
Thread tA = new Thread(t);
Thread tB = new Thread(t);
Thread tC = new Thread(t);
Thread tD = new Thread(t);
tA.start();
tB.start();
tC.start();
tD.start();
}
}