什么是线程

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

使用多线程

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

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. 防御CSRF的方法有哪些(一) HTTP 头中自定义属性并验证 CSRF跨站域请求伪造攻击

    CSRF (Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,该攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在并未授权的情况下 ...

  2. Ajax详解

    一:什么是Ajax AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 不是新的编程语言,而是一种使用现有标准的新方法 ...

  3. knn-伪代码与实现过程

    knn特点 优点:精度高,对异常值不明感,无数据输入嘉定 缺点:计算复杂度高,空间复杂度高 适用范围:数值型和标称型 knn算法的伪代码 1.计算已知类别数据集中的点与当前之间的距离 2.按照距离递增 ...

  4. Codility NumberSolitaire Solution

    1.题目: A game for one player is played on a board consisting of N consecutive squares, numbered from ...

  5. [转]undo log与redo log原理分析

    数据库通常借助日志来实现事务,常见的有undo log.redo log,undo/redo log都能保证事务特性,这里主要是原子性和持久性,即事务相关的操作,要么全做,要么不做,并且修改的数据能得 ...

  6. [NOIP2016]愤怒的小鸟

    题目描述 Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可以用它向第一象限发射一只红色的小鸟,小鸟们的飞行轨迹均为形 ...

  7. 如何基于Azure平台实现MySQL HA(方法论篇)

    我们都知道,相较于传统的数据中心,Pulic cloud也有劣势,比如说数据库的HA,很多熟悉公有云平台的读者都知道,因为出于安全性性考虑以及一些技术条件的限制,很多本地数据中心的mysql HA方法 ...

  8. VB中PictureBox控件使用教程

    PictureBox对象可以说是任何对象的原始型态,它可以加载图片.显示文字.画图外,它还能与Frame对象一样,在自己本身里头加载其它的对象而自成一个小群组,用PictureBox可以仿真出任何对象 ...

  9. 项目vue2.0仿外卖APP(三)

    项目的结构如下:                   项目资源准备 准备项目的各种图片资源等等 注意:在webpack可以不用css sprite,直接用单张图片,因为它会帮忙打包. 还有SVG图片, ...

  10. VS2013全攻略

    http://blog.csdn.net/cpp12341234/article/details/45371269 挺好的,喜欢