JAVA--浅谈线程

来源:互联网 发布:腾讯围棋 mac 编辑:程序博客网 时间:2024/06/05 22:24

写在前面:
以下均为楼主自己理解,请多指正!

  • 线程简介

现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。
进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在Windows系统中,一个运行的exe就是一个进程。
线程是指进程中的一个执行流程,一个进程中可以运行多个线程。比如java.exe进程中可以运行很多线程。线程总是属于某个进程,进程中的多个线程共享进程的内存。

“同时”执行是人的感觉,在线程之间实际上轮换执行。

  • 线程的实现

    1).通过继承Thread类实现线程
    通过创建新的类继承Thread类,重写基类Thread中的run方法即可实现,在需要启动线程的地方,通过Thread中的Start()方法即可实现线程的启动。
    代码实例:

/** *  */package test线程;/** * @author 寒 * */public class TestThread extends Thread{    private String name;    /**     * @param string     */    public TestThread(String string) {        // TODO 自动生成的构造函数存根        this.name = string;    }    public void run(){        for(int i = 0; i < 10 ; i++){            System.out.println("第" + i + "次调用" + this.name + " " + this.getName());        }    }    /**     * @param args     */    public static void main(String[] args) {        // TODO 自动生成的方法存根        new TestThread(" 我是线程0 ").start();        new TestThread(" 我是线程1 ").start();    }}

2).通过实现Runnable接口实现线程
通过Thread thread = new Thread(new Runnable(){});来实现,Runnable接口内包含run()方法,只需在接口内实现该方法并启动即可实现线程。
代码实例:

/** *  */package test线程;import java.awt.BorderLayout;import javax.swing.JFrame;import javax.swing.JProgressBar;/** * @author 寒 * */public class InterruptedSwing extends JFrame{    Thread thread;    /**     * @param args     */    public static void main(String[] args) {        // TODO 自动生成的方法存根        init(new InterruptedSwing(), 300,300);    }    public InterruptedSwing(){        super();        final JProgressBar progressBar = new JProgressBar();        getContentPane().add(progressBar, BorderLayout.NORTH);        progressBar.setStringPainted(true);        thread = new Thread(new Runnable(){            int count = 0;            @Override            public void run() {                // TODO 自动生成的方法存根                while(true){                    progressBar.setValue( ++ count);                    try{                        Thread.sleep(1000);                    }catch(InterruptedException e){                        e.printStackTrace();                    }                }            }        });        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);    }}
  • 线程的休眠
    以下是线程的生命周期示意图,线程包含 出生、就绪、运行、等待、休眠、阻塞、死亡状态。其中线程的休眠使用sleep()方法是实现。使用了sleep()的线程会在一段时间后醒来,但是并不能保证线程醒来后即可进入运行状态,只能进入就绪状态。

    这里写图片描述

    代码实例:

/** *  */package test线程;import java.awt.Color;import java.awt.Graphics;import java.util.Random;import javax.swing.*;/** * @author 寒 * */public class SleepMethodTest extends JFrame{    private Thread t;    private static Color []color = {Color.BLACK,Color.BLUE, Color.CYAN,Color.GREEN,        Color.ORANGE,Color.PINK,Color.YELLOW,Color.WHITE};    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;            @Override            public void run() {                // TODO 自动生成的方法存根                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();    }    /**     * @param args     */    public static void main(String[] args) {        // TODO 自动生成的方法存根        init(new SleepMethodTest(),100 ,100 );    }    public static void init(JFrame jframe , int width , int height){        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        jframe.setSize(width, height);        jframe.setVisible(true);    }}
  • 线程的加入

    线程的加入顾名思义即为将一个线程加入到当前的线程,当前线程会在加入的线程运行完后继续执行,线程的加入使用join()方法,代码实例:

/** *  */package test线程;import java.awt.BorderLayout;import javax.swing.JFrame;import javax.swing.JProgressBar;/** - @author 寒 -  */public class JoinTest extends JFrame {    private Thread threadA;    private Thread threadB;    final JProgressBar progressBar = new JProgressBar();    final JProgressBar progressBar2 = new JProgressBar();    int count = 0;    /**     * @param args     */    public static void main(String[] args) {        // TODO 自动生成的方法存根        init(new JoinTest(), 300, 300);    }    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;            @Override            public void run() {                // TODO 自动生成的方法存根                while (true) {                    progressBar.setValue(++count);                    try {                        Thread.sleep(100);                         threadB.join();//先执行线程B                    } catch (Exception e) {                        e.printStackTrace();                    }                }            }        });        threadA.start();        threadB = new Thread(new Runnable() {            int count = 0;            @Override            public void run() {                // TODO 自动生成的方法存根                while (true) {                    progressBar2.setValue(++count);                    try {                        Thread.sleep(100);                    } catch (Exception e) {                        e.printStackTrace();                    }                    if (count == 100) {                        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);    }}
  • 线程的优先级

1).与线程休眠类似,线程的优先级仍然无法保障线程的执行次序。只不过,优先级高的线程获取CPU资源的概率较大,优先级低的并非没机会执行。
2).线程的优先级用1-10之间的整数表示,数值越大优先级越高,默认的优先级为5。
3).在一个线程中开启另外一个新线程,则新开线程称为该线程的子线程,子线程初始优先级与父线程相同。
4).使用setPriority(int newPriority)方法设置线程的优先级,备选的有三个定义常量Thread.MAX_PRIORITY = 10 、Thread.MIN_PRIORITY = 1、Thread.NORM_PRIORITY= 5,自定义线程优先级的时候范围为1-10的整数。
- 线程的同步
为什么会产生线程的同步的想法?
在多个进程访问公共资源的时候,将会产生bug,示例如下:

package test线程;public class ThreadSafeTest implements Runnable {       int num = 10;    public static void main(String[] args) {        // TODO 自动生成的方法存根        ThreadSafeTest test = new ThreadSafeTest();        Thread thread_a = new Thread(test);        Thread thread_b = new Thread(test);        Thread thread_c = new Thread(test);        Thread thread_d = new Thread(test);        thread_a.start();        thread_b.start();        thread_c.start();        thread_d.start();    }    @Override    public void run() {        // TODO 自动生成的方法存根        while (true) {                if (num > 0) {                    try {                        Thread.sleep(100);                    } catch (Exception e) {                        e.printStackTrace();                    }                    System.out.println(   "tickets  :" + num--);                }                else{                    break;                }        }    }}

运行结果:

tickets  :10tickets  :9tickets  :8tickets  :7tickets  :6tickets  :5tickets  :5tickets  :5tickets  :4tickets  :3tickets  :2tickets  :1tickets  :0tickets  :-1tickets  :-2

在上述线程中,某一线程将票售出,第二个线程也已经完成了判断余票的工作,于是将不存在的票继续出售,产生了线程安全问题,因此继续解决多线程之间对公共资源的访问问题。

线程的同步是利用临界资源的思想来解决问题,当多个线程需要访问一些公有资源的时候,将公有资源上锁,只允许一个进程进行访问。即可解决线程安全问题。使用synchronized(Object){// 公共资源的访问},当其他线程获取到这个锁的时候,必须等待锁被释放才能够进入该区域。Object为任意对象,每个对象都存在一个标志位,并具有0、1两个值,而这个值即为同步锁,线程运行到此处,会首先检查该对象的标志位,如果为0,即表示此同步块在其他线程中运行,此时线程处于就绪状态,反之,进入运行,并修改标志位。

修改上述代码:

@Override    public void run() {        // TODO 自动生成的方法存根        while (true) {            synchronized ("") {                if (num > 0) {                    try {                        Thread.sleep(100);                    } catch (Exception e) {                        e.printStackTrace();                    }                    System.out.println(   "tickets  :" + num--);                }                else{                    break;                }            }        }    }

运行结果:

tickets  :10tickets  :9tickets  :8tickets  :7tickets  :6tickets  :5tickets  :4tickets  :3tickets  :2tickets  :1
1 0