一、线程的概念:
package thread;
/**
* @author xieyongxue
* 线程:是一个程序中的顺序控制流
* 进程与线程的区别:
* 1.每个进程都有独立的代码和数据空间,进程之间的切换都有较大的开销
* 2.线程可以看成轻量级的进程,同一类的线程共享代码和数据空间,独有运行栈和程序计数器,线程之间的切换开销较小
* 3.多进程:在操作系统中可以同时执行多个任务
* 4.多线程:在一个应用程序中有多个顺序流执行
*
*/
/*
* 线程:线程是一个程序中不同的执行路径
*/
public class ThreadTest1 {
public static void main(String[] args) {
t1();
}
public static void t1(){
t2();
t3();
}
public static void t2(){
System.out.println("t2:1");
}
public static void t3(){
System.out.println("t3:2");
}
}
/**
*1.代码分析:
* 这个程序的执行顺序是先从main()方法开始,也就是整个程序的主线程,然后执行t1(),t1()里面然后执行t2()
* 当t2()执行完后,执行t3(),t3()执行完后,t1()的调用也完了,返回main(),main()方法调用完后
* 然后再继续往下执行。
* 2.CPU的执行是这样的:CPU的速度很快,一秒钟可以算好几亿次,因此CPU把自己的时间分成一个个小时间片
* ,我这个时间片执行你一会,下一个时间片执行他一会,再下一个时间片又执行其他人一会,虽然有几十个线程,
* 但一样可以在很短的时间内把他们通通都执行一遍,但对我们人来说,CPU的执行速度太快了,因此看起来就像是在同时执行一样,
* 但实际上在一个时间点上,CPU只有一个线程在运行。
* 3.概念
* 进程:进程是一个静态的概念
线程:一个进程里面有一个主线程叫main()方法,是一个程序里面的,一个进程里面不同的执行路径。
在同一个时间点上,一个CPU只能支持一个线程在执行。因为CPU运行的速度很快,
因此我们看起来的感觉就像是多线程一样。
如果你的机器是双CPU,或者是双核,这确确实实是多线程。
*/
二.线程的使用
第一种方式:
package thread;
/**
* @author xieyongxue
*
*/
//开辟一个新的线程来调用run方法
public class ThreadTest2 {
public static void main(String[] args) {
Runner runner=new Runner();//这里new了一个线程类的对象出来
Thread th=new Thread(runner);//要启动一个新的线程就必须new一个Thread对象出来
//th.run();//这个称为方法调用,方法调用的执行是等run()方法执行完之后才会继续执行main()方法
/*
* 当执行到th.start()时候,开辟一个新的线程,main()线程继续往下执行,新线程方法run()与主线程交替执行
*/
th.start();
for(int i=0;i<10;i++){
System.out.println("main:"+i);
}
}
}
/*定义一个类用来实现Runnable接口,实现Runnable接口就表示这个类是一个线程类*/
class Runner implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
System.out.println("runner:"+i);
}
}
}
第二种方式:
package thread;
/**
* @author xieyongxue
*
*/
//不开辟一个新的线程来调用run方法
public class ThreadTest3 {
public static void main(String[] args) {
Runner1 runner=new Runner1();//这里new了一个线程类的对象出来
Thread th=new Thread(runner);
//方法调用,单线程执行,必须run()执行完后,主线程main()才开始往下执行
th.run();
for(int i=0;i<10;i++){
System.out.println("main:"+i);
}
}
}
/*定义一个类用来实现Runnable接口,实现Runnable接口就表示这个类是一个线程类*/
class Runner1 implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<10;i++){
System.out.println("runner:"+i);
}
}
}
package thread;
/**
* 继承Thread类,并重写其run()方法创建和启动新的线程
* @author xieyongxue
*
*/
public class ThreadTest4 {
public static void main(String[] args) {
Runner3 runner=new Runner3();
runner.start();//调用start()方法启动新开辟的线程
for(int i=0;i<10;i++){
System.out.println("main:"+i);
}
}
}
/**
*
* @author xieyongxue
*Runner3类从Thread类继承
通过实例化Runner2类的一个对象就可以开辟一个新的线程
调用从Thread类继承来的start()方法就可以启动新开辟的线程*/
class Runner3 extends Thread{
@Override
public void run(){//重写run()方法
for(int i=0;i<10;i++){
System.out.println("Runner3:"+i);
}
}
}
三.sleep,join,yield的使用
package thread;
import java.util.Date;
public class ThreadSleep {
public static void main(String args[]) {
MyThread thread = new MyThread();
thread.start();// 调用start()方法启动新开辟的线程
try {
/*
* Thread.sleep(10000);
* sleep()方法是在Thread类里面声明的一个静态方法,因此可以使用Thread.sleep()的格式进行调用
*/
/*
* MyThread.sleep(10000);
* MyThread类继承了Thread类,自然也继承了sleep()方法,所以也可以使用MyThread.sleep()
* 的格式进行调用
*/
/*
* 静态方法的调用可以直接使用“类名.静态方法名” 或者“对象的引用.静态方法名”的方式来调用
*/
MyThread.sleep(10000);
System.out.println("主线程睡眠了10秒种后再次启动了");
// 在main()方法里面调用另外一个类的静态方法时,需要使用“静态方法所在的类.静态方法名”这种方式来调用
/*
* 所以这里是让主线程睡眠10秒种 在哪个线程里面调用了sleep()方法就让哪个线程睡眠,所以现在是主线程睡眠了。
*/
} catch (InterruptedException e) {
e.printStackTrace();
}
// thread.interrupt();//使用interrupt()方法去结束掉一个线程的执行并不是一个很好的做法
thread.flag = false;// 改变循环条件,结束死循环
/**
* 当发生InterruptedException时,直接把循环的条件设置为false即可退出死循环,
* 继而结束掉子线程的执行,这是一种比较好的结束子线程的做法
*/
/**
* 调用interrupt()方法把正在运行的线程打断 相当于是主线程一盆凉水泼上去把正在执行分线程打断了
* 分线程被打断之后就会抛InterruptedException异常,这样就会执行return语句返回,结束掉线程的执行
* 所以这里的分线程在执行完10秒钟之后就结束掉了线程的执行
*/
}
}
class MyThread extends Thread {
boolean flag = true;// 定义一个标记,用来控制循环的条件
public void run() {
/*
* 注意:这里不能在run()方法的后面直接写throw Exception来抛异常,
* 因为现在是要重写从Thread类继承而来的run()方法,重写方法不能抛出比被重写的方法的不同的异常。
* 所以这里只能写try……catch()来捕获异常
*/
while (flag) {
System.out.println("==========" + new Date().toLocaleString() + "===========");
try {
/*
* 静态方法的调用格式一般为“类名.方法名”的格式去调用 在本类中声明的静态方法时调用时直接写静态方法名即可。
* 当然使用“类名.方法名”的格式去调用也是没有错的
*/
// MyThread.sleep(1000);//使用“类名.方法名”的格式去调用属于本类的静态方法
sleep(1000);// 睡眠的时如果被打断就会抛出InterruptedException异常
// 这里是让这个新开辟的线程每隔一秒睡眠一次,然后睡眠一秒钟后再次启动该线程
// 这里在一个死循环里面每隔一秒启动一次线程,每个一秒打印出当前的系统时间
} catch (InterruptedException e) {
/*
* 睡眠的时一盘冷水泼过来就有可能会打断睡眠
* 因此让正在运行线程被一些意外的原因中断的时候有可能会抛被打扰中断(InterruptedException)的异常
*/
return;
// 线程被中断后就返回,相当于是结束线程
}
}
}
}
join的使用:
package thread;
public class ThreadJoin {
public static void main(String[] args) {
MyThread2 myth = new MyThread2();
myth.start();
try {
// 调用join()方法合并线程,将子线程mythread合并到主线程里面
// 合并线程后,程序的执行的过程就相当于是方法的调用的执行过程
myth.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 0; i < 10; i++) {
System.out.println("main:" + i);
}
}
}
class MyThread2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println("MYThread2:" + i);
}
}
}
yield:
package thread;
public class Threadyield {
public static void main(String[] args) {
MyThread3 t1=new MyThread3();
MyThread4 t2=new MyThread4();
t1.start();
t2.start();
for(int i=0;i<5;i++){
System.out.println("main:"+i);
}
}
}
class MyThread3 extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("th1:" + i);
if (i % 2 == 0) {
yield();// 当执行到i能被2整除时当前执行的线程就让出来让另一个在执行run()方法的线程来优先执行
/*
* 在程序的运行的过程中可以看到, 线程t1执行到(i%2==0)次时就会让出线程让t2线程来优先执行
* 而线程t2执行到(i%2==0)次时也会让出线程给t1线程优先执行
*/
}
}
}
}
class MyThread4 extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("th2:" + i);
if (i % 2 == 0) {
yield();// 当执行到i能被2整除时当前执行的线程就让出来让另一个在执行run()方法的线程来优先执行
/*
* 在程序的运行的过程中可以看到, 线程t1执行到(i%2==0)次时就会让出线程让t2线程来优先执行
* 而线程t2执行到(i%2==0)次时也会让出线程给t1线程优先执行
*/
}
}
}
}
原文地址:http://www.cnblogs.com/xdp-gacl/p/3633936.html