JAVA SE(十八)—— JAVA 线程1(基本概念、创建线程、生命周期、Thread类方法、守护线程)

一、线程基本概念

1、 进程 Processor
一块包含了某些资源的独立内存空间,用于存放资源。

2、 线程 Thread
线程是在进程内部同时做的事情,是CPU能够调度的最小单位,一个进程包含至少一个线程,线程与线程是独立的,共享进程里面的资源。

3、单核CPU:同一时间只能干一件事情。

4、CPU调度算法
① 分时调度:比如每个运行50ns;
② 抢占式调度:谁抢到CPU的资源就执行谁,调度算法。JVM虚拟机里面的线程采用抢占式调度。

二、Java中创建线程方式

1、继承Thread类,重写run( )方法
(1)步骤:
① 创建线程对象
② 开启线程,调用 start( ) 方法

(2)Thread创建线程Demo
① 创建一个MyThread1类继承Thread类,

public class MyThread1 extends Thread {
	//创建一个run( )方法
	public void run ( ) {
		for( int i = 0 ; i < 1000 ; i++ ) {
			System.out.println( "这是继承实现的线程" );
		}
	}
}

② 在主方法中创建线程对象并调用方法。

public class Demo1{
	public static void main(String[] args) {
		//创建线程对象
		MyThread1 mt = new MyThread1( );
		//开启线程,调用start( ) 方法,start( ) 会自动调用MyThread类中的run( ) 方法。
		mt.start( );
		//谁抢到CPU资源就运行谁
		for( int j = 0 ; j < 1000 ; j++) {
			System.out.println( "这是main( )方法中的线程" );
		}
	}
}

JVM虚拟机里面的线程采用抢占式调度,所以线程的执行是随机的,哪条线程抢到CPU的执行权,就执行哪条线程,所以上面程序的结果如下(只截取部分):

...
这是第二个线程2
这是第二个线程2
这是继承实现的线程
这是继承实现的线程
这是继承实现的线程
这是继承实现的线程
这是第二个线程2
这是第二个线程2
这是第二个线程2
...

2、实现Runable接口,重run( )方法
(1)Runable创建线程Demo1
① 创建一个类MyThread实现Runnable接口,

public class MyThread2 implements Runnable{
	public void run ( ) {
		for( int i = 0 ; i< 500 ; i++ ) {
			System.out.println( "实现Runable接口创建线程");
		}
	}
}

② 在主方法中创建线程对象并调用方法,运行结果类似Demo1。

public class Demo2 {
	public static void main(String[] args) {
		MyThread2 mt2 = new MyThread2( );
		Thread t2 = new Thread( mt2 );
		t2.start( );
		
		//谁抢到CPU资源就运行谁
		for( int j = 0 ; j < 1000 ; j++) {
			System.out.println( "这是main( )方法中的线程" );
		}
	}
}

(2)示例2
创建一个类继承Thread类

public class MyThread1 extends Thread {
	//创建一个run( )方法
	public void run ( ) {
		for( int i = 0 ; i < 1000 ; i++ ) {
			System.out.println( "这是继承实现的线程" );
		}
	}
}

创建一个类实现Runnable接口

public class MyThread2 implements Runnable{
	public void run ( ) {
		for( int i = 0 ; i< 500 ; i++ ) {
			System.out.println( "实现Runable接口创建线程");
		}
	}
}

主函数类

public class Demo3 {
	public static void main(String[] args) {
		//线程1
		MyThread1 mt = new MyThread1( );
		//开启线程,调用start( ) 方法,start( ) 会自动调用MyThread类中的run( ) 方法。
		mt.start( );
		
		//主线程
		for( int j = 0 ; j < 1000 ; j++) {
			System.out.println( "这是main( )方法中的线程" );
		}
		//线程2
		MyThread2 mt2 = new MyThread2( );
		Thread t2 = new Thread( mt2 );
		t2.start( );
	}
}

运行结果(部分):

...
这是main( )方法中的线程
这是main( )方法中的线程
这是main( )方法中的线程
这是main( )方法中的线程
这是继承实现的线程
这是继承实现的线程
实现Runable接口创建线程
实现Runable接口创建线程
实现Runable接口创建线程
实现Runable接口创建线程
...

3、匿名内部类方式创建线程
(1)匿名内部类方式创建线程Demo

public class Demo {
	//匿名内部类的方式创建线程
	public static void main(String[] args) {
		//第一种
		new Thread() {
			public void run() {
				System.out.println( "线程执行的内容");
			}
		}.start();
		//第二种
		new Thread( new Runnable() {
			public void run() {
				System.out.println( "匿名内部类创建线程");
			}
		}).start();
	}
}

三、线程的生命周期

1、相关概念
(1)新建状态:创建线程对象 new Thread( );
(2)就绪状态:调用start( )后进入就绪状态,就绪状态是进入运行状态的唯一入口(要想进入运行状态必须先进入就绪状态)
(3)运行状态:执行run( )方法里面的内容,获得CPU的使用权;
(4)阻塞状态:处于运行状态的线程,由于某种原因暂时放弃的对CPU的使用权,停止执行,如果想继续运行,必须进入就绪状态,重写争夺CPU资源;

  • 等待阻塞:wait( );
  • 同步阻塞:在等待获取锁资源的时候;
  • 其他阻塞。
    (5)死亡状态:线程执行完run( )方法里面的内容或者因异常退出,该线程生命周期结束。

四、Thread类

1、currentThread( )方法、sleep( )方法、setName( )方法
(1)currentThread( )方法
是返回对当前正在执行的线程对象的引用。

(2)sleep( )方法
① 是在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),sleep()是静态方法,只能控制当前正在运行的线程。
② 线程睡眠是帮助所有线程获得运行机会的最好方法。线程睡眠到期自动苏醒,并返回到可运行状态,不是运行状态。
③ sleep()中指定的时间是线程不会运行的最短时间。因此,sleep()方法不能保证该线程睡眠到期后就开始执行。
MyThread类

public class MyThread4 extends Thread {
	//创建一个run( )方法
	public void run ( ) {
		Thread td = Thread.currentThread( );
		System.out.println( td);		//得到Thread[改名后名字,5,main]
		//线程执行的内容,输出100次"这是继承实现的线程" 
			try {
				for( int i = 0 ; i < 100 ; i++ ) {
					Thread.sleep(1000);
					System.out.println( "这是继承实现的线程" );
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
		}
	}
	//构造函数
	public MyThread4( ) { }
	public MyThread4( String str ) {
		super( str );
	}
}

主函数类

public class Demo4 {
	public static void main(String[] args) {
		Thread ct = Thread.currentThread( );
		System.out.println( ct );		//得到 Thread[main,5,main]
		MyThread4 mt = new MyThread4( );
		//修改名字
		mt.setName( "改名后名字" );
		//开启线程
		mt.start( );
	}
}

运行结果(部分)为:

...
Thread[main,5,main]
Thread[改名后名字,5,main]
这是继承实现的线程
这是继承实现的线程
这是继承实现的线程
...

这里,Thread[main,5,main]是主函数中Thread ct = Thread.currentThread( ); System.out.println( ct ); 语句得到的结果,Thread[改名后名字,5,main] 是主函数调用MyThread类中方法,其方法中的Thread td = Thread.currentThread( ); System.out.println( td); 语句执行得到的结果。
如果不改名字,初始结果应该是 Thread[Thread-0,5,main],其中:
Thread表示类,Thread-0表示线程名,5表示优先级(1-10,默认为5,1最低,10最高),优先级表示获取到CPU资源的概率

(3)setName( )方法是改变线程名称,使之与参数name相同

(4)yield()方法

  • 暂停当前正在执行的线程对象,并执行其他线程。即抢到CPU执行器,但是放弃执行权,降低其概率。
  • yield( )应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。

(5)jion()方法
join()是非静态方法,让一个线程B“加入”到另外一个线程A的尾部。在A执行完毕之前,B不能工作,即让交替运行的线程按照顺序执行。
示例

public class Demo5 {
	// join( )方法,让交替运行的线程按照顺序执行
	public static void main(String[] args) {
		//下载到100% 下载成功
		Thread t1 = new Thread( ) {
			public void run( ) {
				for( int i = 0 ; i < 100 ; i ++ ) {
					try {
						Thread.sleep(100);
						System.out.println( "下载完成" + i + "%" );
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
		};
		Thread t2 = new Thread( ) {
			public void run( ) {
				try {
					for( int j = 0 ; j < 10 ; j++) {
						Thread.sleep(1000);						
						System.out.println( "我要下载了" );
					}
					t1.join( );
					System.out.println( "下载完成" );
				} catch (InterruptedException e) {
					e.printStackTrace( );
				}
			};
		};
		t1.start( );
		t2.start( );
	}
}

五、守护线程

(1)在后台提供一种通用服务的线程,当所有通用线程结束后,该线程自动死亡。

(2)设置为守护线程的方法:setDaemon( boolean on ),将该线程标记为守护线程或用户线程。

(3)示例

public class Demo6 {
	//守护线程示例
	public static void main(String[] args) {
		//通用线程
		Thread t1 = new Thread( "德玛" ) {
			public void run( ) {
				for( int i = 0 ; i < 10 ; i++ ) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace( );
					}
					String name = Thread.currentThread( ).getName( );
					System.out.println( name +  "说:我是德玛西亚" );
				}
				System.out.println( "我现在不是了" );
			};
		};
		//守护线程
		Thread t2 = new Thread( "EZ" ) {
			public void run( ) {
				while( true ) {
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace( );
					}
					String name = Thread.currentThread( ).getName( );
					System.out.println( name +  "说:我是EZ" );
				}
			};
		};
		t2.setDaemon( true );		//设置为守护线程
		t1.start( );
		t2.start( );
	}
}

注意:

  • 设置守护线程必须在start( )方法前设置;
  • 在守护线程内创建的新线程也是守护线程;
  • 守护线程不会去访问固有资源或数据库等,因为该线程随时可能停止;
  • 守护线程会一直概率性执行,直到其他通用线程执行完毕后停止。
发布了40 篇原创文章 · 获赞 0 · 访问量 356

猜你喜欢

转载自blog.csdn.net/baidu_27414099/article/details/104425301
今日推荐