您的位置:首页 > 编程语言 > Java开发

JAVA--浅谈线程

2016-04-21 16:28 731 查看
写在前面:

以下均为楼主自己理解,请多指正!

线程简介

现在的操作系统是多任务操作系统。多线程是实现多任务的一种方式。

进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程。比如在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  :10
tickets  :9
tickets  :8
tickets  :7
tickets  :6
tickets  :5
tickets  :5
tickets  :5
tickets  :4
tickets  :3
tickets  :2
tickets  :1
tickets  :0
tickets  :-1
tickets  :-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  :10
tickets  :9
tickets  :8
tickets  :7
tickets  :6
tickets  :5
tickets  :4
tickets  :3
tickets  :2
tickets  :1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: