什么是线程

线程是操作系统调度的最小单位,一个进程中可以有多个线程,这些线程可以各自的计数器,栈,局部变量,并且能够访问共享的内存变量。多线程的优势是可以提高响应时间和吞吐量。

使用多线程

一个进程正在运行的时候,至少会有一个线程运行。

public class Test {
public static void main(String[] args) {
System.out.println(Thread.CurrentThread().getName()); // 输出main
}
}

上面的程序输出为main,实际上是一个叫做main的线程在执行main方法,输出的main与main方法没有任何关系

继承Thread

实现多线程方式有两种,一种是继承Thread类,另一种是实现Ruannable接口。我们可以看看Thread类的结构

public class Thread implents Runnable

创建自己的线程类MyThread,并且重写run方法。

public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("Mythread");
}
}
public class Run() {
public static void main(String[] args) {
Mythread myThread = new MyThread();
myThread.start():
System.out.println("运行结束");
}
}

上面的输出为

运行结束
MyThread

实现Runnable接口

如果先创建的线程类已经有一个父类了,那么就不能够继承Thread,因为java只支持单继承。那么捏可以实现Runnable接口。

public class MyRunnable imiplements Runnable {
@Override
public void run() {
System.out.println("运行中");
}
}

怎么运行呢?我们看看Thread的构造器?

可以通过将Runnable接口来创建Thread。

public class Run {
public static void main(String[] args) {
Thread thread = new Thread(runnable);
thread.start();
System.out.println("运行结束!");
}
}

实例变量和线程安全

自定义线程类的实例变量针对其他线程有共享和不共享之分,区分它们对于线程安全非常重要。

线程不共享数据的情况

public MyThread extends Thread {
private int count = 5;
public MyThread(String name) {
super();
this.setName(nanme); //线程的名字
}
@Override
public void run(){
super.run();
while(count > 0 ) {
count--;
System.out.println("由"+this.currentThread().getName() +" 计算. count=" + count);
} }
} public class Run {
public static void main(String[] args) {
MyThread a = new MyThread("A");
MyThread b = new MyThread("B");
MyThread c = new MyThread("C");
a.start();
b.start();
c.start();
}
}

共享数据如何实现呢?



public class MyThread extends Thread {

    private int count = 5;

    @Override
public void run() {
super.run();
while(count > 0) {
count--;
System.out.println("由" + this.currentThread().getName() + "计算,count =" + count);
}
}
}
public class Run() {
public static void main(String[] args) {
MyThread mythread = new MyThread();
Thread a = new Thread(mythread, "A");
Thread b = new Thread(mythread, "B");
Thread c = new Thread(mythread, "C");
a.start();
b.start();
c.start();
} }

上面的线程共享了MyThread中的count数据,所以上面的代码是线程不安全的。解决这种问题,最简单的方式,是通过同步的手段来达到线程安全的目的。

currentThread方法

在Thread类中有一个currentThread方法,这个方法可以查看当前线程的信息,比如当前线程的名称。

isAlive方法

用来判断当前线程是否处于活动状态,什么是活动状态,活动状态就是线程已经启动且没有终止。

sleep()方法

方法sleep方法是指在指定的毫秒数内让当前正在执行的线程来休眠。当前正在执行的线程是指this.currentThread()的结果。

停止线程

Java中有以下方式终止正在进行的线程:

  • 使用退出标识,使线程正常退出,也就是当run方法完成后线程终止
  • 使用stop方法强行终止线程,但是不推荐使用,因为stop和suspend都是过期的方法
  • 使用intterrupt方法来中断线程

停止不了的线程

下面的例子调用intterrupt()方法来停止线程,但是interrupt方法的使用效果并不是for+break那样,调用interrupt方法仅仅是在当前线程中打一个停止的标记

public class MyThread extends Thread {
@Override
public void run() {
super.run();
for(int i = 0 ; i < 50000; i++) {
System.out.println("i = " + (i + 1));
}
}
} public class Run {
public static void main(String[] args) {
try {
MyThread my_thread = new MyThread();
my_thread .start();
Thread.sleep(2000);
my_thread.interrupt();
} catch(InterruptException e) {
System.out.println("main catch");
e.printStackTrace();
}
} }

结果是,仍然打印了50万行的日志,所以调用interrupt方法并没有停止线程。

判断线程是否是停止状态

Thread类中,有两种方法:

  • this.interrupted(),测试当前线程是否已经中断
  • this.isInterrupted(),测试线程是否已经中断

我们来看看this.interrupted()方法的解释:测试当前线程是否已经中断,当前线程是指执行这个方法调用的线程。

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

我们通过thread.interrupted()用来测试当前线程是否是已经中断,而在这里当前线程为main线程,而它从未中断过。所以打印的结果是两个false

看看下面的代码:

public class Run2 {
public static void main(String[] args) {
Thread.currentThread().interrupt();
System.out.println("是否停止1 ? " + Thread.interrrupted()); // true
System.out.println("是否停止2 ? " + Thread.interrrupted()); // false
System.out.println("end");
}
}

方法interrupted()的确判断出当前线程是否停止,但为什么第二个为false值呢?看看interrrupted方法的手册说明:

测试当前线程是否已经中断。线程中断状态由该方法清除。换句话说,如果连续两次调用该方法,则第二次调用将返回false(在第一次调用已清除了其中断状态之后,且第二次调用检验完中断前,当前线程再次中断的情况除外)。

Tests whether the current thread has been interrupted. The interrupted status of the thread is cleared by this method. In other words, if this method were to be called twice in succession, the second call would return false (unless the current thread were interrupted again, after the first call had cleared its interrupted status and before the second call had examined it)

也就是所interrupted()方法具有清除状态的方法,所以第二次调用interrupted()方法返回的值是false。

我们来看看interrupted()方法后再来看看isInterrupted()方法,声明如下:

public boolean isInterrupted();

从声明中可以看出isInterrupted()方法不是static的。

public class Run3 {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(1000);
thread.interrupt();
System.out.println("是否停止1 ?==" + thread.isInterrupted()); // true
System.out.println("是否停止2? ==" + thread.isInterrupted()); // true
} catch(InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
System.out.println("end")
} }

我们可以看到this.isInterrrupted()并未清除状态标志,所以打印两个true。

我们总结一下,两个方法的解释:

  • this.interrupted() : 测试当前线程是否已经是中断的状态,执行后具有将状态标志清除为false的功能。
  • this.isInterrupted(): 测试线程Thread对象是否已经是中断状态,但不清除状态标志。

能停止的线程--异常法

public calss MyThread extends Thread {
@Override
public void run() {
super.run();
for(int i = 0; i < 50000; i++) {
if(this.interrupted()) {
System.out.println("已经是停止状态!我要退出!");
break;
}
System.out.println("i=" + (i + 1));
}
}
}
public class Run {
public static void main(String[] args) {
try {
MyThread thread =new MyThread();
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch(InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
}
}
}

上面的示例虽然停止了线程,但如果for语句下面还有语句,还是会继续运行的。


public calss MyThread extends Thread {
@Override
public void run() {
super.run();
for(int i = 0; i < 50000; i++) {
if(this.interrupted()) {
System.out.println("已经是停止状态!我要退出!");
break;
}
System.out.println("i=" + (i + 1));
}
System.out.println("我被输出,如果此代码是for又继续运行,线程并未停止!");
}
} public class Run {
public static void main(String[] args) {
try {
MyThread thread = new MyThread() ;
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch(InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
} }
}

上面的代码可以将我被输出,如果此代码是for又继续运行,线程并未停止!输出了。说明,及时停止了线程,从for循环中跳出,for后面的语句也会执行。这说明了一个什么问题:thread.interrupt只是打一个标志,表示通知该线程要停止,而this.interrupted()则只是能够检测这个标志,并且将这个标志服务清除。

那么怎么讲线程停止呢?

public calss MyThread extends Thread {
@Override
public void run() {
try {
super.run();
for(int i = 0; i < 50000; i++) {
if(this.interrupted()) {
System.out.println("已经是停止状态!我要退出!");
throw new InterruptedException();
break;
}
System.out.println("i=" + (i + 1));
}
System.out.println("我被输出,如果此代码是for又继续运行,线程并未停止!");
} catch (InterrruptedException e) {
System.out.println("进MyThread.java类run方法中的catch了");
}
}
} public class Run {
public static void main(String[] args) {
try {
MyThread thread = new MyThread() ;
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch(InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
} }
}

在睡眠中停止

如果线程在sleep状态下,会有什么效果呢?

public calss MyThread extends Thread {
@Override
public void run() {
try {
super.run();
System.out.println("run begin")
Thread.sleep(20000); //睡觉20s
System.out.println("run end");
} catch (InterrruptedException e) {
System.out.println("在睡觉中被停止,进入catch!" + this.isInterrupted()); // 结果打印false。
}
}
}
public class Run {
public static void main(String[] args) {
try {
MyThread thread = new MyThread() ;
thread.start();
Thread.sleep(2000);
thread.interrupt();
} catch(InterruptedException e) {
System.out.println("main catch");
e.printStackTrace();
} }
}

从结果上看,如果在sleep状态下停止某一线程,那么,会进入到catch语句,并且清楚停止状态值,使其成为false。

暂停线程

暂停线程意味着线程可以恢复执行,在java多线程中,可以使用suspend()方法暂停线程,使用resume()方法恢复线程的执行。

public class MyThread extends Thread {
private long i = 0;
public long getI() {
return i;
}
public void setI(int i) {
this.i = i;
}
@Override
public void run() {
while(true) {
i++;
}
}
} public class Run {
public static void main(String[] args) {
try {
MyThread thread = new MyThread();
thread.start();
Thread.sleep(5000);
thread.suspend();
System.out.println("A=" + System.currentTimeIillis() + " i =" + thread.getI());
Thread.sleep(5000);
System.out.println("A=" + System.currentTimeMIillis() + " i =" + thread.getI()); // B段
thread.resume();
Thread.sleep(5000);
// C段
thread.suspend();
System.out.println("B= " + System.currentTimeMillis() + " i = " + thread.getI());
Thread.sleep(5000);
System.out.println("B = " + System.currentTimeMillis() + " i = " + thread.getI() ); } catch(InterruptedException e) {
e.printStackTrace();
}
} }

suspend和resumen方法的缺点--独占

如果一个线程获取了某个资源的锁,但是其suspend,那么后续的线程就无法获取该锁。

yield方法

这个方法用来放弃当前的CPU资源,将它然给其他的任务去占用CPU执行时间。但是放弃的时间不确定,有可能刚放弃,马上又获得了时间片。

A hint to the scheduler that the current thread is willing to yield its current use of a processor. The scheduler is free to ignore this hint.

Java并发编程基础--基本线程方法详解的更多相关文章

  1. java并发编程(七)synchronized详解

    Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码.     一.当两个并发线程访问同一个对象object中的这个synchronized( ...

  2. Java 并发编程(一) → LockSupport 详解

    开心一刻 今天突然收到花呗推送的消息,说下个月 9 号需要还款多少钱 我就纳了闷了,我很长时间没用花呗了,怎么会欠花呗钱? 后面我一想,儿子这几天玩了我手机,是不是他偷摸用了我的花呗 于是我找到儿子问 ...

  3. Java并发编程基础

    Java并发编程基础 1. 并发 1.1. 什么是并发? 并发是一种能并行运行多个程序或并行运行一个程序中多个部分的能力.如果程序中一个耗时的任务能以异步或并行的方式运行,那么整个程序的吞吐量和可交互 ...

  4. 并发-Java并发编程基础

    Java并发编程基础 并发 在计算机科学中,并发是指将一个程序,算法划分为若干个逻辑组成部分,这些部分可以以任何顺序进行执行,但与最终顺序执行的结果一致.并发可以在多核操作系统上显著的提高程序运行速度 ...

  5. Java并发编程系列-(2) 线程的并发工具类

    2.线程的并发工具类 2.1 Fork-Join JDK 7中引入了fork-join框架,专门来解决计算密集型的任务.可以将一个大任务,拆分成若干个小任务,如下图所示: Fork-Join框架利用了 ...

  6. Java并发编程--基础进阶高级(完结)

    Java并发编程--基础进阶高级完整笔记. 这都不知道是第几次刷狂神的JUC并发编程了,从第一次的迷茫到现在比较清晰,算是个大进步了,之前JUC笔记不见了,重新做一套笔记. 参考链接:https:// ...

  7. Java多线程编程中Future模式的详解

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  8. Java多线程编程中Future模式的详解<转>

    Java多线程编程中,常用的多线程设计模式包括:Future模式.Master-Worker模式.Guarded Suspeionsion模式.不变模式和生产者-消费者模式等.这篇文章主要讲述Futu ...

  9. Java中的equals和hashCode方法详解

    Java中的equals和hashCode方法详解  转自 https://www.cnblogs.com/crazylqy/category/655181.html 参考:http://blog.c ...

随机推荐

  1. Alpha版总结会议

    昨天上课的时候,我们学习了项目总结这一部分的内容,并根据老师提供的项目Postmortem模板对我们的项目进行了总结. 项目Postmortem模板主要分为设想和目标.计划.资源.变更管理.设计和实现 ...

  2. 纯CSS 图片演示

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xht ...

  3. 监视 Windows 剪切板

    一.先看代码 import win32con,win32gui import win32clipboard as cb class MyWindow(): def __init__(self): #注 ...

  4. Ubuntu安装SSH服务器故障分析及解决办法(错误1:E:软件包 openssh-server 还没有可供安装的候选者,错误2:E: 无法修正错误,因为您要求某些软件包保持现状,就是它们破坏了软件包间的依赖关系)

    •    微博: 小样儿老师2015 Windows下做Linux开发需要SSH强大功能的支持.安装SSH的过程会出现了很多问题,看完这篇文章可以让你少走些弯路,PS:折腾一下午的成果. Ubuntu ...

  5. java IO输入输出流中的各种字节流,字符流类

    字节流字节流主要是操作byte类型数据,也byte数组为准,主要操作类就是·字节输出流:OutputStream·字节输入流:InputStream字符流在程序中一个字符等于2个字节,那么java提供 ...

  6. 关于python装饰器

    关于python装饰器,不是系统的介绍,只是说一下某些问题 1 首先了解变量作用于非常重要 2 其次要了解闭包 def logger(func): def inner(*args, **kwargs) ...

  7. C#中用radio单选Repeater循环数据,js实现

    <asp:Repeater ID="rpt" runat="server"> <ItemTemplate> <tr data-id ...

  8. git服务器搭建总结

    1.软件选择 服务端软件:由于我对linux还不熟悉,而且公司用的都是windows,于是找到了bonobo,这是一个基于.net framework 4.5和.net mvc4的开源软件,iis7. ...

  9. 枚举扩展方法获取枚举Description

    枚举扩展方法 /// <summary> /// 扩展方法,获得枚举的Description /// </summary> /// <param name="v ...

  10. WPF DataGrid 性能加载大数据

    WPF(Windows Presentation Foundation)应用程序在没有图形加速设备的机器上运行速度很慢是个公开的秘密,给用户的感觉是它太吃资源了,WPF程序的性能和硬件确实有很大的关系 ...