关闭

多线程编程-Java线程概述(一)

标签: Java线程基本概念interrruptedinInterrupted
21人阅读 评论(0) 收藏 举报
分类:

一,Java多线程技能

1.1  进程和多线程的概念

可以把一个正在操作系统中运行的程序理解为一个“进程”。进程是受操作系统管理的基本运行单元。

 

线程可以理解为在进程中独立运行的子任务。当打开浏览器,下载文件的同时,还可以打开看视频,这些功能就对应了多个线程在后台运行。使用多线程就是在使用异步,因为每个线程被调用的时机是随机的。

 

1.2  继承Thread类,实现Runnable接口。

实现多线程的方式有两种,一是继承Thread类,一是实现Runnable接口。

Thread类也实现了Runnable接口,他们之间具有多态关系。

继承Thread类,最大的局限是不能多继承,所以为了支持多继承,可以实现Runnable

接口。

       使用多线程时,代码的运行结果与代码执行顺序或调用顺序是无关的。

       调用threadstart方法启动的线程,是交给“线程规划器”安排处理,具有异步执行的效果;如果调用代码thread.run方法就不是异步执行了,而是同步,这个线程对象并不交给“线程规划器”处理,而是由main线程来调用run方法,也就是要等到run方法代码执行完才能执行后面的代码。

      

       实现的Runnable接口,可以作为参数传给Thread类的构造函数。同时因为Thread类也实现了Runnable接口,所以也可以将一个Thread类对象传给Thread类的构造函数,实现吧把一个Thread对象中的run方法交由其他线程调用。

 

       在多线程数据共享的情况下,可以通过synchronized关键字,synchronized关键字可以在任意对象及方法上加锁,而加锁的这段代码成为“互斥区”或“临界区”。

 

       多线程操作中有个“非线程安全”的术语,主要是指多个线程对同一个对象中同一个实例变量进行操作时会出现值被更改、值不同步的情况,进而影响到程序的执行流程。

      

1.3  currentThread()可返回代码段正在被那个线程调用的信息。如果没有调用threadstart方法,是不会创建新的线程的,它的run方法还是运行在原来的线程中。

 

1.4  isAlive() 判断当前线程是否处于活动状态。

活动状态就是线程已经启动且尚未终止,线程处于正在运行或准备运行的状态。

 

1.5  sleep()作用是在指定的毫秒内让当前“正在执行的线程”休眠(暂停执行),这个“正在执行的线程”是指this.currentThread()返回的线程。

 

1.6  getId()方法的作用是取得线程的唯一标识。    

 

1.7  停止线程。

大多数停止一个线程的操作使用Thread.interrupt()方法,尽管方法的名称是“停止,终止”的意思,但这个方法不会终止一个正在运行的线程,还需要加入一个判断才可以完成线程的停止。

 

Java中有3中方法可以终止正在运行的线程:

1) 使用退出标志,是线程正常退出,也就是当run方法完成后线程终止。

2) 使用stop方法强行终止线程,但是这个方法已经被作废了,因为stopsuspendresume一样,都被作废了,他们可能产生不可预料的结果。

3) 使用interrupt方法终止线程。

 

1.7.1调用interrupt()方法仅仅是在当前线程中打了一个停止标记,并不是真的停止线程。

 

	ThreadDemo threadDemo = new Thread();
	threadDemo.interrrupt();//并没有停止线程。

1.7.2 判断线程是否是停止状态

       Thread.java类里提供了两个方法:

1)  this.interrrupted();测试当前线程是否已经中断。

2)  this.inInterrupted();测试线程是否已经中断。

 

Interrupted()方法,测试当前线程是否已经中断,当前线程是指运行this.interrupted()方

法的线程,比如:

class MyThread extends Thread{
	@Override
	public void run(){
		super.run();
		for(int i=0; i<500000; i++){
			System.out.println("i="+i);
		}
	}
}	
	
public class ThreadDemo {
	public static void main(String[] args) {
		try{
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(500);
			thread.interrupt();
			System.out.println("是否停止 1? ="+thread.interrupted());
			System.out.println("是否停止 2? ="+thread.interrupted());
		}catch(InterruptedException e){
			System.out.println("Main catch");
			e.printStackTrace();
		}
		System.out.println("Main end.");
	}
}

运行结果:

i=98140

是否停止 1? =false

i=98141

i=98224

是否停止 2? =false

Main end.

i=98225

从控制台输出结果看,MyThread线程并未停止,运行:thread.interrupted()这句代码的当前线程是main,它从未中断过,所以结果是false

 

将上面的测试代码改为:


MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(500);
			//thread.interrupt();
//这会把主线程中断。
			Thread.currentThread().interrupt();
			System.out.println("是否停止 1? ="+thread.interrupted());
			System.out.println("是否停止 2? ="+thread.interrupted());

运行结果:

i=89376

是否停止 1? =true

i=89377

….

i=89620

是否停止 2? =false

i=89621

 

第一个bool值,判断出主线程是停止状态,第二个bool值false,表示:线程的中断状态由该方法清除,所以再次调用interrupted()返回值是false。

 

在看另一个方法isInterrupted(),

测试代码:


MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(500);
			thread.interrupt();
			System.out.println("是否停止 1? ="+thread.isInterrupted());
			System.out.println("是否停止 2? ="+thread.isInterrupted());	

运行结果:

i=94353

是否停止 1? =true

是否停止 2? =true

Main end.

i=94354

 

isInterrupted()方法不是static的,它是实例方法,测试的MyThread这个线程是不是暂停了,并且不会清除状态标记。

1.7.3 能停止的线程-异常法

       借用前面的代码,MyThreadrun方法修改如下,其他不变: 

class MyThread extends Thread{
	@Override
	public void run(){
		super.run();
		try{
			for(int i=0; i<500000; i++){
				System.out.println("i="+i);
				if(this.interrupted()){
					System.out.println("线程已经停止,退出运行。");
					//break;
					throw new InterruptedException();
				}
			}
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
}

运行结果:  

i=95742

线程已经停止,退出运行。

Main end.

java.lang.InterruptedException

    atMyThread.run(ThreadDemo.java:11)

 

上面的代码中,如果只是调用break退出for循环,for循环之后的代码还是会继续执行,我们的目标是想要在判断出线程停止后,run中的语句不在继续执行,通过抛出异常的方式可以实现这个目标。

也可以通过return实现停止线程的效果,但是还是抛异常的方法更好,因为这个异常会继续往上抛,使线程停止的事件得以传播。

 

1.1 暂停线程

Java多线程中,可以使用suspend()方法暂停线程,是用resume()方法恢复线程的执行。

测试代码

class MyThread extends Thread{
	private long i= 0;
	public long getI(){
		return i;
	}
	public void setI(long i){
		this.i = i;
	}
	@Override
	public void run(){
		while(true){
			i++;
		}
	}
}

public class SuspendResumeDemo {

	public static void main(String[] args) {
		try{
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(1000);
			thread.suspend();
			System.out.println("A= "+System.currentTimeMillis()+", i="+thread.getI());
			Thread.sleep(1000);
			System.out.println("A++= "+System.currentTimeMillis()+", i="+thread.getI());
			
			thread.resume();
			Thread.sleep(1000);
			
			thread.suspend();
			System.out.println("B= "+System.currentTimeMillis()+", i="+thread.getI());
			Thread.sleep(1000);
			System.out.println("B++= "+System.currentTimeMillis()+", i="+thread.getI());
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
}

运行结果:

A= 1515399519208, i=458693572

A++= 1515399520208, i=458693572

B= 1515399521210, i=915434631

B++= 1515399522211, i=915434631

从时间信息、i的值可以看出,线程被暂停了,又被恢复运行了。

 

1.8.2 suspend(),resume()方法都是被废弃的,因为他们使用不当,容易造成公共的同步对象的独占,使得其他线程无法访问公共的同步对象。

测试代码:

class SynchronizedObject{
	synchronized public void printString(){
		System.out.println("bengin");
		if(Thread.currentThread().getName().equals("a")){
			System.out.println("a 线程 suspend了。");
			Thread.currentThread().suspend();
		}
		System.out.println("end");
	}
}

public class SuspendResumeDemo {

	public static void main(String[] args) {
		try{
			final SynchronizedObject object = new SynchronizedObject();
			Thread thread1 = new Thread(){
				@Override
				public void run(){
					object.printString();
				}
			};
			thread1.setName("a");
			thread1.start();
			Thread.sleep(1000);
			
			Thread thread2= new Thread(){
				@Override
				public void run(){
					System.out.println("thread2 启动了,但无法进入printString()方法体,因为这个方法被a线程锁定,并且a线程现在暂停了。");
					object.printString();
				}
			};
			thread2.start();
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
}

运行结果:

bengin

a 线程 suspend了。

thread2 启动了,但无法进入printString()方法体,因为这个方法被a线程锁定,并且a线程现在暂停了。

 

另外,还有一种独占锁的情况,测试代码:

class MyThread extends Thread{
	private long i= 0;
	@Override
	public void run(){
		while(true){
			i++;
		}
	}
}

public class SuspendResumeDemo {

	public static void main(String[] args) {
		try{
			MyThread thread = new MyThread();
			thread.start();
			Thread.sleep(1000);
			thread.suspend();
			System.out.println("main end");
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
}

运行结果:

main end

 

这个结果没有什么意外,但是修改下代码:

While循环中加了一句打印。

class MyThread extends Thread{
	private long i= 0;
	@Override
	public void run(){
		while(true){
			i++;
			System.out.println("i="+i);
		}
	}
}

运行结果:

i=199905

i=199906

i=199907

i=199908

没有打印 "main end"

没有打印 "main end"的原因,看下println的源码:


public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
}

当程序运行到println()方法内部停止时,同步锁不会释放,所以main方法的这句:System.out.println("mainend");不能执行打印。

 

1.8.3 suspend(),resume()方法的缺点---不同步

使用suspend(),resume()时,容易因为线程的暂停而导致数据不同步的情况。

测试代码:

class MyObject{
	private String username = "1";
	private String password = "111";
	
	public void setValue(String u, String p){
		this.username = u;
		if(Thread.currentThread().getName().equals("a")){
			System.out.println("a线程停止!!!");
			Thread.currentThread().suspend();
		}
		this.password = p;
	}
	
	public void printUserNamePassword(){
		System.out.println(username+"---"+password);
	}
}
public class SuspendResumeDemo {

	public static void main(String[] args) {
		try{			
			MyObject myobject = new MyObject();
			Thread thread1 = new Thread(){
				@Override
				public void run(){
					myobject.setValue("a", "aaa");
				}
			};
			thread1.setName("a");
			thread1.start();
			Thread.sleep(500);
			
			Thread thread2 = new Thread(){
				@Override
				public void run(){
					myobject.printUserNamePassword();
				}
			};
			thread2.start();
			
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
}

运行结果:

a线程停止!!!

a---111

 

usernamepassword出现了不同步的情况。

 

1.1yield方法

yield()方法的作用是放弃当前的CPU资源,将它让给其他的任务去占用cpu执行时间。但是放弃的时间不确定,有可能刚刚放弃,马上有获得cpu时间片。

Thread.yield();

 

1.2守护线程

Java中有两种线程,一种是用户线程,一种是守护线程。

守护线程是一种特殊的线程,特性是:当进程中不存在非守护线程时,守护线程才自动销毁。只要当前JVM实例中存在任何一个非守护线程没有结束,守护线程就在工作,只有当最后一个非守护线程结束时,守护线程才随着JVM一同结束。

典型的守护线程是垃圾回收线程GC。

通过thread1.setDaemon(true);标记一个线程是守护线程,这个方法要在start方法之前调用。


0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

【Java】线程并发、互斥与同步

网络上对于线程的解析总是天花龙凤的,给你灌输一大堆概念,考研、本科的操作系统必修课尤甚,让你就算仔细看完一大堆文章都不知道干什么。 下面不取网站复制粘贴,在讲解自己的Java线程并发、互斥与同步之前先...
  • yongh701
  • yongh701
  • 2015-01-17 09:22
  • 2485

关于java中的锁的理解(通俗易懂)

这是我看过的极好的一篇关于锁的机制的介绍,通俗易懂,非常好,采纳,接受,给赞
  • u012291108
  • u012291108
  • 2016-05-08 23:41
  • 3746

线程的基本概念、线程的基本状态以及状态之间的关系

什么是线程 一个线程是进程的一个顺序执行流。同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈。线程在切换时负荷小,因此,线程也被称为轻负荷进程。一个进程中可以包含多...
  • BornLiLi
  • BornLiLi
  • 2017-02-19 16:53
  • 5427

Java多线程编程3--线程间通信实例--等待/通知之交叉备份

题目:创建20个线程,其中10个线程是将数据备份到A数据库中,另外10个线程将数据备份到B数据库中,并且备份A数据库和B数据库是交叉进行的。     首先创建出20个线程,效果如图3-41所示。 ...
  • oChangWen
  • oChangWen
  • 2016-05-05 22:21
  • 552

Java多线程编程3--线程间通信--类ThreadLocal与类InheritableThreadLocal的使用

类ThreadLocal的使用     变量值的共享可以使用public stati。变量的形式,所有的线程都使用同一个publicstatic变量。如果想实现每一个线程都有自己的共享变量该如何解决...
  • oChangWen
  • oChangWen
  • 2016-05-07 10:44
  • 723

java多线程编程学习笔记---线程的创建

线程的理解,线程就是一个进程的一个子任务,即一个线程就是一个任务流程。一般,一个进程的线程会轮流被执行,他们共享进程资源,能够方便进行通信和同步。 1、线程的创建
  • huangxun08
  • huangxun08
  • 2015-01-06 10:22
  • 230

Java多线程编程基础之线程对象

在进入java平台的线程对象之前,基于基础篇(一)的一些问题,我先插入两个基本概念。   [线程的并发与并行]   在单CPU系统中,系统调度在某一时刻只能让一个线程运行,虽然这种调试机制...
  • zk1113
  • zk1113
  • 2016-03-30 12:22
  • 88

Java多线程编程基础之线程对象

多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。              在进行java平台的线程对象之前,先看看二个基本概念...
  • farreaching665
  • farreaching665
  • 2011-12-20 17:24
  • 319

(二)拒绝单一,用不同的方法实现线程--java 多线程编程的那点小事

是不是不管一个线程任务有多简单,都要重新new 一个java class ?当然不是,java 中线程的实现非常灵活,下面就具体讲下如何通过不同的方式来实现一个线程; 一、使用“Thread...
  • yinjingyu_bisheng
  • yinjingyu_bisheng
  • 2013-08-13 10:29
  • 567

Java多线程编程-(8)-两种常用的线程计数器CountDownLatch和循环屏障CyclicBarrier

前几篇: Java多线程编程-(1)-线程安全和锁Synchronized概念 Java多线程编程-(2)-可重入锁以及Synchronized的其他基本特性 Java多线程编程-(...
  • bntX2jSQfEHy7
  • bntX2jSQfEHy7
  • 2017-10-14 00:00
  • 138
    个人资料
    • 访问:35523次
    • 积分:1686
    • 等级:
    • 排名:千里之外
    • 原创:130篇
    • 转载:38篇
    • 译文:0篇
    • 评论:9条
    最新评论