多线程基础知识
来源:互联网 发布:我的购物车淘宝网登录 编辑:程序博客网 时间:2024/06/15 14:46
java多线程
进程
什么是进程
进程是操作系统结构的基础,是资源分配的基本单位,也是独立运行的基本单位。
进程的两个基本属性
- 进程是一个拥有资源的独立单位
- 进程同时是一个可以被处理器独立调度和分配的单位
为什么会有线程?
操作系统为了能让进程并发执行,还需要创建进程、撤销进程和进程切换,进行这些操作时,
操作系统要为进程分配资源及回收资源,为运行进程保留现场信息,这些工作都需要付出较多的时空开销。
所以为了能让程序更好的并发执行,尽量减小操作系统的开销,操作系统设计者引入了线程,让线程去完成第二个基本属性的任务,而进程只完成第一个基本属性的任务。线程是进程中独立运行的子任务。
一个进程正在运行的时候至少会有一个线程在运行。
实现多线程编程的方式
1、继承Thread类,事实上Thread类本身也是实现Runnable接口
2、实现了Runnable接口
运行线程
It is never legal to start a thread more than once.In particular, a thread may not be restarted once it has completedexecution.
使用Thread时需要调用start方法才能让线程开始运行,但是多次调用start方法会产生异常,即使run方法执行结束了也不行!
Exception in thread "main" java.lang.IllegalThreadStateException
多线程是异步的,线程被调用的时机也是随机的。
但是如果调用的是Thread类的run方法,那么就是同步执行的了。因为只有调用start方法才能让线程开始执行。
多线程共享数据的时候可能会产生不同步的问题,那么我们可以使用synchronized关键字,synchronized可以在任意对象及方法上加锁,而加锁的这段代码成为“互斥区”或“临界区”。
currentThread()方法可以返回代码段正在被哪个线程调用的信息。
public static native Thread currentThread();
isAlive()方法的作用是判断当前线程是否处于活动状态(线程已经启动且尚未终止,线程处于正在运行或准备开始运行的状态,就认为线程是“存活”的)。
public final native boolean isAlive();
sleep()的作用是让正在执行的线程(Thread.currentThread())休眠(暂停执行)。
getId()方法的作用是取得线程的唯一标识。
计算线程id的方法是同步的
/* For generating thread ID */private static long threadSeqNumber;private static synchronized long nextThreadID() { return ++threadSeqNumber;}
在java多线程中,停止一个线程有3种方法:
1、让run方法正常执行完毕后线程终止
2、使用stop()方法强行停止,但是该方法已经作废过期,不推荐使用。
因为如果强制让线程停止可能使一些清理性的工作得不到完成。还可能让锁定的对象得不到解锁,导致数据得不到同步的处理,出现数据不一致的问题。
3、使用interrupt方法中断线程
interrupt方法
interrupt方法并不会让线程停止,它只是一个状态标志,需要在run方法内部加上判断才可以。
interrupt方法有两个方法
private native boolean isInterrupted(boolean ClearInterrupted);public boolean isInterrupted() { return isInterrupted(false);}public static boolean interrupted() { return currentThread().isInterrupted(true);}
细心的看一下就会发现这是两个不同的方法。
isInterrupted()是测试线程是否已经是中断状态,不会清除中断状态。
interrupted()是测试当前线程是否已经是中断状态,而且会清除中断状态。
线程睡觉的时候调用interrupt会出现异常,并且清除中断状态
java.lang.InterruptedException: sleep interrupted
可以使用异常法或者return方法终止线程,抛出异常,则run方法的代码不再执行。
//return法class MyThread extends Thread { private int count = 0; @Override public void run() { while (true) { System.out.println(++count); System.out.println(this.getName()); if (this.isInterrupted()) { return; } } }}
异常法是一种不错的方法,因为catch块中可以将异常向上抛,使得线程停止的事件得以传播。
在java多线程中,可以使用suspend方法暂停线程,使用resume方法恢复线程的执行。
但是这两个方法都已经被弃用了,不推荐使用,因为这两个方法容易造成公共的同步对象独占,使得其它线程无法方访问公共同步对象。
package me.mymilkbottles.Study01;/** * Created by Administrator on 2017/07/14 18:54. */public class SuspendResume { public static void main(String[] args) { MyThread1 thread = new MyThread1(); thread.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } thread.doSome2(); }}class MyThread1 extends Thread { @Override public void run() { doSome1(); } synchronized private void doSome1() { System.out.println("do some 1"); this.suspend(); System.out.println("do some 1 end"); } synchronized public void doSome2() { System.out.println("do some 2"); }}
上面这段代码,永远也无法进入doSome2方法了。
还有一种独占锁的情况:
package me.mymilkbottles.Study01;/** * Created by Administrator on 2017/07/14 18:54. */public class SuspendResumeLock2 { public static void main(String[] args) throws Exception { MyThread2 thread = new MyThread2(); thread.start(); Thread.sleep(200); thread.suspend(); System.out.println("ok"); }}class MyThread2 extends Thread { private int count = 0; @Override public void run() { while (true) { System.out.println(++count); } }}
这段代码永远也无法打印ok,因为println的内部是同步的
public void println(String x) { synchronized (this) { print(x); newLine(); }}
但是因为suspend导致无法释放锁,导致ok无法打印。
suspend和resume方法还容易因为线程的暂停导致数据不同步。
yield()方法的作用是放弃当前cpu的资源,将它让给其它的任务去占用cpu,但是放弃的时间不确定,可能刚放弃又重新获得了cpu时间片。
package me.mymilkbottles.Study01;import java.sql.Time;/** * Created by Administrator on 2017/07/14 19:26. */public class Yield { public static void main(String[] args) { outputTime(new MyThread3()); outputTime(new MyThread3Yield()); } private static void outputTime(Thread thread) { long time1 = System.currentTimeMillis(); thread.start(); try { thread.join(); } catch (InterruptedException e) { e.printStackTrace(); } long time2 = System.currentTimeMillis(); System.out.println((time2 - time1) + "ms"); }}class MyThread3 extends Thread { private int count = 0; private static final int TIMES = 1000000; @Override public void run() { for (int i = 0; i <= TIMES; ++i) { count += i; } System.out.println(count); }}class MyThread3Yield extends Thread { private int count = 0; private static final int TIMES = 1000000; @Override public void run() { for (int i = 0; i <= TIMES; ++i) { this.yield(); count += i; } System.out.println(count); }}/*执行结果:178429366423ms1784293664219ms */
因为使用了yield,所以MyThread3Yield类的run方法执行时间慢于MyThread3类的run方法。
线程的优先级
线程可以划分优先级,优先级高的线程得到的cpu资源较多,也就是cpu优先执行优先级高的线程对象中的任务。
(PS:但是这种东西最后还是要看操作系统的意思,只是说优先级高的可以优先执行,没说一定先执行)
package me.mymilkbottles.Study01;/** * Created by Administrator on 2017/07/14 19:42. */public class ThreadPriority { public static void main(String[] args) { Thread[] threads = new Thread[10]; for (int i = 0; i < 10; ++i) { threads[i] = new Thread(new Runnable() { @Override public void run() { for (int j = 1; j < 5; ++j) { System.out.println(Thread.currentThread().getName() + " : " + j); } } }); threads[i].setPriority(i + 1); threads[i].setName(String.valueOf(i)); } for (Thread thread : threads) { thread.start(); } }}/*执行结果:0 : 15 : 12 : 11 : 16 : 11 : 22 : 22 : 32 : 44 : 14 : 24 : 34 : 40 : 25 : 25 : 35 : 49 : 10 : 38 : 11 : 36 : 21 : 43 : 13 : 23 : 33 : 40 : 48 : 27 : 19 : 27 : 28 : 36 : 38 : 47 : 37 : 49 : 36 : 49 : 4*/
线程的优先级具有继承性,如果A线程启动B线程,则B线程的优先级和A一样。
守护线程
java线程中有两种线程,一种是用户线程,另外一种是守护线程。
当线程中不存在非守护线程的时候,守护线程自动销毁,典型的守护线程就是垃圾回收线程。
Daemonde的作用就是为其它线程的运行提供便利服务。
线程的几种状态:
Thread.State.TERMINATED;Thread.State.BLOCKED;Thread.State.NEW;Thread.State.RUNNABLE;Thread.State.TIMED_WAITING;
线程组:可以批量的管理线程或线程组对象,有效地对线程或线程组对象进行组织。
线程自动归属特性:自动归属就是自动归到当前线程组中。
使用ThreadGroup的interrupt方法时,可以将组中的所有正在运行的线程批量停止。
- 多线程基础知识
- 多线程基础知识
- 多线程基础知识
- 多线程基础知识
- 多线程基础知识
- 多线程基础知识
- 多线程基础知识
- 多线程基础知识
- 多线程基础知识
- 多线程基础知识
- Java多线程基础知识
- Java多线程基础知识
- java多线程基础知识
- 多线程的基础知识
- Java多线程基础知识
- 多线程的基础知识
- 多线程编程基础知识
- 基础知识——多线程
- x264源代码简单分析:x264_slice_write()
- Java反射的简单应用
- 深入浅出JMS(二)--ActiveMQ简单介绍以及安装
- PAT-乙级 1016.部分A+B(15)
- 二级列表数据从网络请求数据
- 多线程基础知识
- WEB集群与负载均衡
- Java精选笔记_JSP技术
- Servlet 编写过滤器
- Java eclipse乱码解决问题
- Android:最全面的 Webview 详解
- php配置项目时候的小技巧
- WPF 值转换器
- mysql字符集相关汇总