网站开发与应用专业,做网站一般什么问题,基于h5的企业网站建设,住房和建设局20.1线程简介. 20.2创建线程
2.1继承Thread类
Thread 类是java.lang包中的一个类#xff0c;从这个类中实例化的对象代表线程#xff0c;程序员启动一个新线程需要建立Thread 实例。Thread类中常用的两个构造方法如下: public Thread():创建一个新的线程对象。 public Thre…20.1线程简介. 20.2创建线程
2.1继承Thread类
Thread 类是java.lang包中的一个类从这个类中实例化的对象代表线程程序员启动一个新线程需要建立Thread 实例。Thread类中常用的两个构造方法如下: public Thread():创建一个新的线程对象。 public Thread(String threadName):创建一个名称为threadName的线程对象。 继承Thread 类创建一个新的线程的语法如下: public class ThreadTest extends Thread{ } 完成线程真正功能的代码放在类的run(方法中当一个类继承Thread类后就可以在该类中覆盖 run()方法将实现该线程功能的代码写入run()方法中然后调用Thread类中的start()方法执行线程也就是调用run()方法。 Thread 对象需要一个任务来执行任务是指线程在启动时执行的工作该工作的功能代码被写在 run()方法中。run()方法必须使用以下语法格式: public void run(){ } 注意如果 start()方法调用一个已经启动的线程系统将抛出IllegalThreadStateException异常。 2.2实现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对象的构造方法创建Thread实例。(3)调用start()方法启动线程。 通过 Runnable接口创建线程时程序员首先需要编写一个实现 Runnable接口的类然后实例化该类的对象这样就建立了Runnable对象;接下来使用相应的构造方法创建 Thread 实例;最后使用该实例调用Thread类中的 start()方法启动线程。 import java.awt.Container;import javax.swing.JFrame;
import javax.swing.JLabel;public class SwingAndThread extends JFrame{int count 0;public SwingAndThread(){setBounds(300,200,250,100); //绝对定位窗体大小与位置 Container container getContentPane(); //主容器 container.setLayout(null); //使窗体不使用任何布局管理器 lcon icon new lmagelcon(/D20/src/1.gif); //图标对象 JLabel jl new JLabel(icon); //显示图标的标签 jl.setBounds(10,10,200,50); //设置标签的位置与大小 Thread t new Thread(){ //定义匿名线程对象 public void run() {while (true) {jl.setBounds(count,10,200,50); //将标签的横坐标用变量表示 try{Thread.sleep(500); //使线程休眠 500毫秒 } catch (InterruptedException e){e.printStackTrace();}count 4; //使横坐标每次增加4 if (count 200){count 10; //当图标到达标签的最右边时使其回到标签最左边 }}}}; t.start(); container.add(jl); //启动线程 //将标签添加到容器中 setVisible(true); //使窗体可见 setDefaultCloseOperation(EXIT_ON_CLOSE); //设置窗体的关闭方式}public static void main(String[] args) {new SwingAndThread();}}20.3线程的生命周期
线程具有生命周期其中包含7种状态分别为出生状态、就绪状态、运行状态、等待状态、休眠状态、阻塞状态和死亡状态。出生状态就是线程被创建时处于的状态在用户使用该线程实例调用 start()方法之前线程都处于出生状态;当用户调用start()方法后线程处于就绪状态(又被称为可执行状态);当线程得到系统资源后就进入运行状态。 一旦线程进入可执行状态它会在就绪与运行状态下转换同时也有可能进入等待、休眠、阻塞或死亡状态。当处于运行状态下的线程调用Thread类中的wait()方法时该线程便进入等待状态进入等待状态的线程必须调用Thread类中的notify0方法才能被唤醒而调用notifyAl1O)方法可将所有处于等待状态下的线程唤醒;当线程调用Thread类中的sleep(方法时则会进入休眠状态。如果一个线程在运行状态下发出输入/输出请求该线程将进入阻塞状态在其等待输入/输出结束时线程进入就绪状态对于阻塞的线程来说即使系统资源空闲线程依然不能回到运行状态。当线程的run()方法执行完毕时线程进入死亡状态。 说明 使线程处于不同状态下的方法会在20.4节中进行讲解在此读者只需了解线程的多个状态即可。 20.4操作线程的方法
4.1线程的休眠 import java.awt.*;import java.util.Random; import javax.swing.*;public class SleepMethodTest extends JFrame {private static Color[]color{ Color.BLACK, Color.BLUE,Color.CYAN,Color.GREEN,Color.ORANGE, Color.YELLOW, Color.RED,Color.PINK,Color.LIGHT_GRAY};//定义颜色数组private static final Random randnew Random(); //创建随机对象 private static Color getC(){ //获取随机颜色值的方法 return color[(rand.nextInt(color.length))];}public SleepMethodTest() {Thread t new Thread(new Runnable() {//创建匿名线程对象 int x30; Il定义初始坐标 int y50;public void run(){while (true) { //无限循环 try{ Thread.sleep(100); //线程休眠 0.1秒 } catch (InterruptedException e){e.printStackTrace();Graphics graphicsgetGraphics(); //获取组件绘图上下文对象 graphics.setColor(getC()); //设置绘图颜色 graphics.drawLine(x,y,100,y); //绘制直线并递增垂直坐标 if (y 80) {y 50;}}}});t.start(); //启动线程 }public static void main(String[]args){init(new SleepMethodTest(),100,100);}public static void init(JFrame frame, int width, int height){//初始化程序界面的方法frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(width, height); frame.setVisible(true);}}
4.2线程的加入
使用join方法加入线程
import java.awt.BorderLayout;
import javax.swing.*;
public class JoinTest extends JFrame {
private Thread threadA; //定义两个线程
private Thread threadB;
private JProgressBar progressBar new JProgressBar(); //定义两个进度条组件
private JProgressBar progressBar2new JProgressBar();
public static void main(String[] args) {JoinTest test new JoinTest(); test.setVisible(true);public JoinTest(){setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(200,200,200,100);getContentPane().add(progressBar, BorderLayout.NORTH); //将进度条设置在窗体最北面 getContentPane().add(progressBar2,BorderLayout.SOUTH); //将进度条设置在窗体最南面progressBar.setStringPainted(true); //设置进度条显示数字字符 progressBar2.setStringPainted(true);threadA new Thread(new Runnable() { //使用匿名内部类形式初始化 Thread实例 int count 0;public void run() { //重写 run()方法 while (true) {progressBar.setValue(count); //设置进度条的当前值 try {Thread.sleep(100); //使线程A 休眠 100毫秒 threadB.join(); //使线程B调用 join()方法 }catch (InterruptedException e){e.printStackTrace();}}}});threadA.start(); //启动线程AthreadB new Thread(new Runnable(){int count 0;public void run() {while (true) {progressBar2.setValue(count); //设置进度条的当前值 try{ Thread.sleep(100); //使线程B休眠 100 毫秒 } catch (InterruptedException e) {e.printStackTrace();if (count 100) break; //跳出循环 }}}); //启动线程B threadB.start();}} 4.3线程的中断
现在提倡在r un()方法中使用无限循环的形式然后使用一个布尔型标记控制循环的停止。 如果线程是因为使用了sleep()或 wait()方法:进入了就绪状态可以使用Thread 类中interrupt)方法使线程离开run()方法同时结束线程但程序会会抛出 InterruptedException异常用户可以在处理该异常时完成线程的中断业务处理如终止while 循环。 下面的实例演示了某个线程使用interrupted0方法同时程序抛出了InterruptedException异常在异常处理时结束了while循环。在项目中经常在这里执行关闭数据库连接和关闭Socket连接等操作。
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;public class InterruptedSwing extends JFrame {public InterruptedSwing(){JProgressBar progressBar new JProgressBar(); //创建进度条 getContentPane().add(progressBar, BorderLayout.NORTH);//将进度条放置在窗体合适位置JButton buttonnew JButton(停止);getContentPane().add(button,BorderLayout.SOUTH);progressBar.setStringPainted(true); //设置进度条上显示数字 Thread t new Thread(new Runnable(){int count 0; public void run() {while (true){progressBar.setValue(count);//设置进度条的当前值try{ Thread.sleep(100); //使线程休眠 100毫秒 } catch (InterruptedException e){//捕捉InterruptedException 异常System.out.println(当前线程序被中断); break;}}}});button.addActionListener(new ActionListener(){Overridepublic void actionPerformed(ActionEvent e){t.interrupt(); //中断线程 }}); t.start(); //启动线程 }public static void init(JFrame frame, int width, int height) {frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(width, height); frame.setVisible(true);}public static void main(String[] args){init(new InterruptedSwing(),100,100);}} 4.4线程的礼让
Thread类中提供了一种礼让方法使用 yield()方法表示它只是给当前正处于运行状态的线程一 个提醒告知它可以将资源礼让给其他线程 但这仅是一种暗示没有任何一种机制保证当前线程会将资源礼让。 yield()方法使具有同样优先级的线程有过进入可执行状态的机会,在当前线程放弃执行权时会再度回到就绪状态。对于支持多任务的操作系统来说不需要调用yield()方法因为操作系统会为线程自动分配 CPU 时间片来执行。
20.5线程的优先级 public class PT implements Runnable {String name;public PT(String name) {this.name name; }Overridepublic void run() {String tmp ;for (int i 0; i 50000; i) {tmp i;
//完成5万次字符串拼接}System.out.println(name 线程完成任务);}public static void main(String[]args){Thread a new Thread(new PT(A));a.setPriority(1); //A线程优先级最小 Thread b new Thread(new PT(B));b.setPriority(3);Thread c new Thread(new PT(C)); c.setPriority(7); Thread d new Thread(new PT(D));d.setPriority(10); //D线程优先级最大 a.start(); b.start(); c.start(); d.start(); }} 线程的优先级可以使用setPriority()方法调整如 果使用该方法设置的优先级不在1~10将产生 IllegalArgumentException 异常。
20.6线程同步
在单线程程序中每次只能做一件事情后面的事情需要等待前面的事情完成后才可以进行但是如果使用多线程程序就会发生两个线程抢占资源的问题如两个人同时说话、两个人同时过同一个独木桥等。所以在多线程编程中需要防止这些资源访问的冲突。Java提供了线程同步的机制来防止资源访问的冲突。 6.1 线程安全 实际开发中使用多线程程序的情况很多在编写多线程程序时应该考虑到线程安全问题实质上线程安全问题来源于两个线程同时存取单一对象的数据。
public class ThreadSafeTest implements Runnable {//设置当前总票数int num 10;public void run() {//设置无限循环while (true) {if (num 0){ //判断当前票数是否大于0 try {Thread.sleep(100); //使当前线程休眠100毫秒 } catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() ----票数 num--);//票数减1}}}public static void main(String[]args){ThreadSafeTest t new ThreadSafeTest(); //实例化类对象 Thread tA new Thread(t,线程一); //以该类对象分别实例化4个线程 Thread tB new Thread(t,线程二); Thread tC new Thread(t,线程三); Thread tD new Thread(t,线程四);tA.start(); //分别启动线程 tB.start(); tC.start();tD.start();}
}从这个结果可以看出最后打印出的剩下的票数为负值这样就出现了问题。这是由于同时创建了4个线程这4个线程执行run()方法在num变量为1时线程一、线程二、线程三、线程四都对num 变量有存储功能当线程一执行run()方法时还没有来得及做递减操作就指定它调用sleep()方法进入就绪状态统等。这种多线程的 这时线程二、线程三和线程四也都进入了run()方法发现num 变 如果大于0则执行 量依然大于 0但此时线程一休眠时间已到将num变量值递减张票)第一个线程 同时线程二、线程三、线程四也都对num变量进行递减操作从 而产生了负值。
6.2线程同步机制
1.同步块 Java 中提供了同步机制可以有效地防止资源冲突。同步机制使用synchronized关键字 语法如下: synchronized (Object){ } 通常将共享资源的操作放置在synchronized定义的区域内这样当其他线程获取到这个锁时就必须等待锁被释放后才可以进入该区域。Object为任意一个对象每个对象都存在一个标志位并具有两个值分别为0和1。一个线程运行到同步块时首先检查该对象的标志位如果为0状态表明此同步块内存在其他线程这时当期线程处于就绪状态直到处于同步块中的线程执行完同步块中的代码后这时该对象的标识位设置为1当期线程才能开始执行同步块中的代码并将Object对象的标识位设置为0以防止其他线程执行同步块中的代码。
public class SynchronizedTest implements Runnable { int num 10;//设置当前总票数public void run() {while (true){ //设置无限循环 synchronized (this){ //设置同步代码块 if (num 0) { //判断当前票数是否大于0 try {Thread.sleep(100); //使当前线程体眠 100} catch (InterruptedException e) {e.printStackTrace();}//票数减 1System.out.println(Thread.currentThread().getName()--票数 num--);}}}}public static void main(String[] args){//实例化类对象SynchronizedTest t new SynchronizedTest();//以该类对象分别实例化4个线程 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();}}
2.同步方法
同步方法就是在方法前面用synchronized关键字修饰的方法其语法如下: synchronized void f(){} 当某个对象调用了同步方法时该对象上的其他同步方法必须等待该同步方法执行完毕后才能被执行。必须将每个能访问共享资源的方法修饰为synchronized否则就会出错。 修改例20.7的代码将共享资源操作放置在一个同步方法中代码如下:
int num 10;
public synchronized void doit() { //定义同步方法
if(num0){
try{
Thread.sleep(10);
}catch(interruptedException e){
e.printStackTrace():
System.out.printin(Thread.currentThread().getName()-票数” num--);
public void run(){while(true){
doit(): //在run()方法中调用该同步方法