多线程初步了解

线程简介:

Java语言提供了并发机制,程序员可以在程序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机制被称为多线程。
一个线程则是进程中的执行流程,一个进程中可以同时包括多个线程,每个线程也可以得到一小段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。在单线程中,程序代码按调用顺序依次往下执行,如果需要一个进程同时完成多段代码的操作,就需要产生多线程。
在java中主要提供两种方式实现线程,分别为继承java.lang.Thread类与实现java.lang.Runnable接口。

这里稍微扯点别的: 多进程与多线程有哪些区别呢?
本质的区别在于每个进程拥有自己的一整套变量,而线程则共享数据。共享变量使得线程之间的通信比进程之间的通信更有效、更容易。在个别的操作系统中,与进程相比较,线程更“轻量级”,创建、撤销一个线程比启动新进程的开销要小得多。

继承Thread类

从Thread类中实例化的对象代表线程,启动一个线程则需要建立Thread实例。

常用的两个构造方法如下:
public Thraed(String threadName)
创建一个名次为threadName的线程对象。

public class ThreadTest extends Thread{
}
继承Thread类创建一个新的线程的语法如上:
完成线程真正的功能的代码放在类的run()方法中,当一个类继承Thread类后,就可以在该类中覆盖run()方法,将实现该线程功能的代码写入run()方法中,然后同时调用Thread类中的start()方法执行线程,也就是调用run()方法。
下列代码是 ThreadTest类继承Thread类方法创建线程。

package 多线程;

public class ThreadTest 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 ThreadTest().start();
    }
}

输入结果如下:
10 9 8 7 6 5 4 3 2 1
通常在run方法中使用无限循环的形式,使得线程一直运行下去,所以必须指定一个跳出条件。
如果不调用start()方法,线程永远都不会启动,在主方法没有调用start()方法之前,Thread对象只是一个实例,而不是一个真正的线程。

实现Runnable接口

如果需要继承其他类(非Thread类),而且还要使当前类实现多线程,那么就可以通过Runnable接口来实现。
使用Runnable接口启动新的线程的步骤如下:
(1)建立Runnable对象。
(2)使用参数为Runnable对象的构造方法创建Thread实例。
(3)调用start()方法启动线程。

这里创建SwingAndThread类继承JFrame类,实现图标移动。

package 多线程;
import java.awt.*;
import java.net.URL;
import javax.swing.*;

public class SwingAndThread extends JFrame{
    private JLabel jl = new JLabel();
    private static Thread t;
    private int count = 0;
    private Container container = getContentPane();

    public SwingAndThread(){
        setBounds(300,200,250,100);
        container.setLayout(null);
        URL url = SwingAndThread.class.getResource("/1.png");//添加一个名称为1的png格式图
        Icon icon = new ImageIcon(url);
        jl.setIcon(icon);
        jl.setHorizontalAlignment(SwingConstants.LEFT);
        jl.setBounds(10,10,200,50);
        jl.setOpaque(true);
        t = new Thread(new Runnable(){
            public void run(){
                while(count <= 200){
                    jl.setBounds(count, 10, 200, 50);
                    try{
                        Thread.sleep(1000);
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                    count += 4;
                    if(count == 200){
                        count = 10;
                    }
                }
            }
        });
        t.start();
        container.add(jl);
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }
    public static void main(String[] args){
        new SwingAndThread();
    }
}

这里run()方法中主要是循环图标的横坐标位置,当图标横坐标到达标签的最右方时,再次将图标的横坐标置于图标滚动的初始位置。
有一点需要注意:启动一个新线程,不是直接调用Thread子类对象的run()方法,而是调用 Thread子类的start()方法,Thread类的start()方法产生一个新线程,该线程运行Thread子类的run()方法。

线程的生命周期

线程具有生命周期,其中包含7种状态,分别为出生状态,就绪状态,运行状态,等待状态,休眠状态,阻塞状态和死亡状态。
(1)在用户使用该线程实例调用start()方法之前线程都处于出生状态。
(2)当用户调用start()方法后,线程处于就绪状态(又被称为可执行状态)。
(3)当线程得到系统资源后就进入运行状态。
(4)当处于运行状态下的线程调用Thread类中的wait()方法时,该线程便进入等待状态。
(5)当线程调用Thread类中的sleep()方法时,则会进入休眠状态。
(6)当一个线程在运行状态下发出输入/输出请求,该线程将进入阻塞状态。在其等待输入/输出结束时线程进入就绪状态。对于阻塞的线程来说,即使系统资源空闲,线程依然不能回到运行状态。当线程的run()方法执行完毕时,线程进入死亡状态。
(7)线程因如下两个原因之一而被终止:
因为run方法正常退出而自然死亡。
因为一个没有捕获的异常终止了run方法而意外死亡。
特别的注意 stop方法已经过时,不要调用这个方法。
虽然多线程看起来像同时执行,但事实上在同一个时间点上只有一个线程被执行,只是线程之间切换较快,所以才会使人产生线程是同时进行的假象。

线程的休眠

这里我们调用sleep()方法来控制线程行为。

try{
        Thread.sleep(100);
    }catch(InterruptedException e){
        e.printStackTrace();
    }

上述代码会使线程在2秒之内不会进入就绪状态。由于sleep()方法的执行有可能抛出InterruptedException异常,所以将sleep()方法的调用放在try/catch块中。虽然使用了sleep()方法的线程在一段时间内会醒来,但是并不能保证它醒来后来入运行状态,只能保证它进入就绪状态。
创建SleepMethodTest类继承JFrame类,实现在窗体中自动画线段的功能,并且为线段设置颜色,颜色是随机产生的。

package 多线程;

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

import javax.swing.JFrame;


public class SleepMethodTest extends JFrame{
    private Thread t;
    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 rand = new Random();
    private static Color getC(){
        return color[rand.nextInt(color.length)];
    }
    public SleepMethodTest(){
        t = new Thread(new Runnable(){
            int x = 30;
            int y = 50;
            public void run(){
                while(true){
                    try{
                        Thread.sleep(100);
                    }catch(InterruptedException e){
                        e.printStackTrace();
                    }
                    Graphics graphics = getGraphics();
                    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 heigth){
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(width, heigth);
        frame.setVisible(true);
    }
}

getC()方法用于随机产生Color类型的对象,并且在产生线程的匿名内部类中使用getGraphics()方法获取Graphics对象,使用该对象调用setColor()方法为图形设置颜色。

线程的加入

在多线程程序中,存在一个线程A,现在需要插入线程B,并要求线程B先执行完毕,然后再继续执行线程A,此时可以使用Thread类中的join()方法来完成。
创建JoinTest类继承JFrame类。该实例包括两个进度条,进度条的进度由线程来控制,通过使用join()方法使上面的进度条必须等待下面的进度条完成后才可以继续。

package 多线程;

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JProgressBar;

public class JoinTest extends JFrame{
    private Thread threadA;
    private Thread threadB;
    final JProgressBar progressBar = new JProgressBar();
    final JProgressBar progressBar2 = new JProgressBar();
    int count = 0;
    public static void main(String[] args){
        init(new JoinTest(),100,100);
    }
    public JoinTest(){
        super();
        getContentPane().add(progressBar, BorderLayout.NORTH);
        getContentPane().add(progressBar2, BorderLayout.SOUTH);
        progressBar.setStringPainted(true);
        progressBar2.setStringPainted(true);
        threadA = new Thread(new Runnable(){
            int count = 0;
            public void run(){
                while(true){
                    progressBar.setValue(count++);
                    try{
                        Thread.sleep(100);
                        threadB.join();
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                }
            }
        });
        threadA.start();
        threadB = new Thread(new Runnable(){
            int count = 0;
            public void run(){
                while(true){
                    progressBar2.setValue(++count);
                    try{
                        Thread.sleep(100);
                    }catch(Exception e){
                        e.printStackTrace();
                    }
                    if(count == 100){
                        count = 0;
                        break;
                    }
                }
            }
        });
        threadB.start();
    }
    public static void init(JFrame frame, int width, int height){
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(width, height);
        frame.setVisible(true);
    }
}

在本实例中同时创建了两个线程,这两个线程分别负责进度条的滚动。在线程A的run()方法中使线程B的对象调用join()方法,而join()方法使当前运行线程暂停,直到调用join()方法的线程执行完毕后再执行,所以线程A等待线程B执行完毕后再开始执行,也就是下面的进度条滚动完毕后上面的进度条才开始滚动。

线程的优先级

每个线程都具有各自的优先级,线程的优先级可以表明在程序中该线程的重要性,如果有很多线程处于就绪状态,系统会根据优先级来决定首先使哪个线程进入运行状态。但这并不意味着低优先级的线程得不到运行,而只是它运行的几率比较小,如垃圾回收线程的优先级就较低。
线程的优先级可以使用setpriority()方法调整,如果使用该方法设置的优先级不在1~10之内,将产生IllegalArgumentExceptiion异常。

创建PriorityTest类实现了Runnable接口。创建4个进度条,分别由4个线程来控制,并且为这4个线程设置不同的优先级。

package 多线程;

import javax.swing.JFrame;
import javax.swing.JProgressBar;

public class PriorityTest extends JFrame{
    private Thread threadA;
    private Thread threadB;
    private Thread threadC;
    private Thread threadD;
    final JProgressBar progressBar = new JProgressBar();
    final JProgressBar progressBar2 = new JProgressBar();
    final JProgressBar progressBar3 = new JProgressBar();
    final JProgressBar progressBar4 = new JProgressBar();
    public PriorityTest(){
        threadA = new Thread(new MyThread(progressBar));
        threadB = new Thread(new MyThread(progressBar2));
        threadC = new Thread(new MyThread(progressBar3));
        threadD = new Thread(new MyThread(progressBar4));
        setPriority("threadA",5,threadA);
        setPriority("threadB",5,threadB);
        setPriority("threadC",5,threadC);
        setPriority("threadD",5,threadD);
    }
    public static void setPriority(String threadName, int priority, Thread t){
        t.setPriority(priority);
        t.setName(threadName);
        t.start();
    }
    public static void main(String[] args){
        init(new PriorityTest(), 100, 100);
    }
    //省略非关键代码
    private final class MyThread implements Runnable{
        private final JProgressBar bar;
        int count = 0;
        private MyThread(JProgressBar bar){
            this.bar = bar;
        }
        public void run(){
            while(true){
                bar.setValue(count+=10);
                try{
                    Thread.sleep(1000);
                }catch(InterruptedException e){
                    System.out.println("当前线程被中断");
                }
            }
        }
    }
    public static void init(JFrame frame, int width, int height){
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(width, height);
        frame.setVisible(true);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值