首页 > 代码库 > java 线程详解
java 线程详解
5月7号 周末看了一下线程方面的内容 ,边看视频边看书还附带着参考了很多人的博客,一天的收获,写下来整理一下;感觉收获还是挺多的;过段时间可能看完java 这几大块要去看一下关于spring boot 的内容顺便 也整理一下;附上我参考的 几本书;
关于java 线程,首先要了解一下线程和进程之间的关系、区别以及他们之间的概念;
首先是线程:
- 什么是线程?
线程是在程序执行过程中能够执行部分代码的一个执行单元,也看看做是一个轻量级的进程;线程是程序内的程序控制流只能使用程序内分配给程序的资源和环境
- 关于线程在java语音中的五种状态
- 新建
- 就绪 :可运行状态 表示已经准备就绪但是没有抢占到cpu 资源;处于等待状态
- 运行 :得到cpu 资源,正在运行的状态
- 阻塞 :当线程运行中需要处理IO类操作,不需要用到cpu 资源的时候,便产生这种状态;
- 死亡 :线程出现异常或者 run()方法结束
关于进程
- 什么是进程
进程是指正在执行的一种程序(注意:程序是一种静态的概念,进程是一种动态的概念),可以包含多个线程,多个进程的内部数据和状态都是完全独立的
线程与进程之间的比较
- 线程可以看做是一个轻量级进程;一个进程中可以存在多个线程,各个线程之间共享程序(进程)的内存空间、进程资源
- 各个线程之间拥有独立的栈空间
- 线程 的创建和切换比进程的开销更小;
多线程
- 多线程是指在单个程序中运行不同的线程执行不同的任务(在java 中指 一个程序交替执行不同的代码)
- 目的: 最大限度的利用cpu资源,当某一线程不需要使用cpu 资源时,让正在等待cpu 资源的线程使用;
- 一般我们所运行的java程序 main方法所运行的就是一个主线程;
接下来回归到java ,java 中目前常用实现线程的方式
- 继承Thread 类重写里面的Run()方法
- 实现Runnable 接口并事项该接口的run() 方法
- 实现Callable 接口重写 call()方法 、
1.先从 Thread 直接 上代码 部分讲解都会在 代码注释中呈现出来 ,
多线程操作注意事项:
- 必须调用它的start 方法启动线程 只有通过start 方法 实现的才是 线程 如果直接启用RUn()方法 就是一个普通类而已;
- 正常如果多个线程同时 执行的话 ,看cpu核数,单核的话:宏观并行,微观串行;多核cpu可以做到微观并行;正常现在的电脑已经没有单核的了;
- Thread 也是实现了Runnable 方法的 然后对其进行封装的;
下面是常用的三种线程开启使用方法代码:(这两种方法 不提供直接返回值的)
/** * Created by 杨一 on 2017/5/3. */ public class 多线程 { public static void main(String[] args){ /* 调用它的 start 方法 启动线程 start 方法 先回 去准备好线程所使用的系统资源然后去调用Run 方法; * */ ThreadTest1 threadTest = new ThreadTest1(); Thread threadTest2 = new Thread(new ThreaTest2()); threadTest.start(); threadTest2.start(); } } /* * 创建一个线程类 使它继承一个Thread * */ class ThreadTest1 extends Thread { /* 重写run()方法*/ @Override public void run() { super.run(); for(int i=0;i<100;i++) { System.out.println("继承Thread,重写run()方法"+i); } } } /* * 创建一个线程类 使它继承一个Thread * */ class ThreaTest2 implements Runnable{ @Override public void run() { for(int i=0;i<100;i++) { System.out.println("实现Runnable接口 ,重写run()方法"+i); } } }
下面这种线程是se1.5引入的新特性 Callable接口(可以实现带返回值)
public class 多线程 { public static void main(String[] args) throws ExecutionException, InterruptedException { /* *//* 调用它的 start 方法 启动线程 start 方法 先回 去准备好线程所使用的系统资源然后去调用Run 方法; * *//* ThreadTest threadTest = new ThreadTest(); Thread thread = new Thread(threadTest); Thread thread1 = new Thread(threadTest); thread.start(); thread1.start();*/ /* callable 的使用*/ CallableTest callableTest = new CallableTest(); FutureTask<String> futureTask = new FutureTask<String>(callableTest); Thread thread = new Thread(futureTask); thread.start(); System.out.println(futureTask.get()); } } /* callable 实现带返回参数的线程 */ class CallableTest implements Callable<String> { @Override public String call() throws Exception { String aa = "线程中返回的值"; return aa; } }
关于线程停止 本身 stop()方法 是不安全的 关于原因参考:http://blog.csdn.net/jiangwei0910410003/article/details/19900007
一般停止的话 只需要让run()方法不在执行就可以让它自动销毁;代码:
/* * 创建一个线程类 使它继承一个Thread * */ class ThreadTest1 extends Thread { private boolean flag = true; /* 重写run()方法*/ @Override public void run() { super.run(); /* 用while 循环类结束线程 */ while (flag) { for (int i = 0; i < 100; i++) { System.out.println("继承Thread,重写run()方法" + i); } } } }
接下来是关于 多线程同步的问题 :
- 不同的线程对相同对象中的成员变量操作的时候 是你相互影响的
- 不同的线程对对象中的局部变量不会影响;
代码:
public class 多线程 { public static void main(String[] args) { /* 调用它的 start 方法 启动线程 start 方法 先回 去准备好线程所使用的系统资源然后去调用Run 方法; * */ ThreadTest threadTest = new ThreadTest(); Thread thread = new Thread(threadTest); Thread thread1 = new Thread(threadTest); thread.start(); thread1.start(); } } class ThreadTest implements Runnable { int a; @Override public void run() { /*int a = 0;*/ while (true){ System.out.println("数字"+a++); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } if(a==20){ break; } } } }
成员变量 和部分变量产生的结果;
java synchronized : 参考:http://blog.csdn.net/luoweifu/article/details/46613015
- java中每个对象都有一个锁(lock)或者监视器(monitor)当访问该对象的syncronized方法时即表示对该对象上锁;
- 对于线程来说一旦上锁之后被访问,其他线程将不能再去访问,除非上一个线程被释放或者死亡;、
- 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
public class 多线程 { public static void main(String[] args) throws ExecutionException, InterruptedException { /* *//* 调用它的 start 方法 启动线程 start 方法 先回 去准备好线程所使用的系统资源然后去调用Run 方法; * *//* ThreadTest threadTest = new ThreadTest(); Thread thread = new Thread(threadTest); Thread thread1 = new Thread(threadTest); thread.start(); thread1.start();*/ /* callable 的使用*/ /* CallableTest callableTest = new CallableTest(); FutureTask<String> futureTask = new FutureTask<String>(callableTest); Thread thread = new Thread(futureTask); thread.start(); System.out.println(futureTask.get());*/ SyncTest syncTest = new SyncTest(); Thread thread1 = new Thread(syncTest); thread1.start(); Thread thread2 = new Thread(syncTest); thread2.start(); } } /* Syncchronized */ class SyncTest implements Runnable{ @Override public void run() { synchronized (this){ for(int i =5;i>0;i--) { System.out.println(Thread.currentThread().getName()+"--i" +i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
锁定方法:
锁定类的方法:
/* Syncchronized 锁定方法 */ class SyncTest implements Runnable{ @Override public void run() { /* 对 类 加锁 */ synchronized (SyncTest.class){ for(int i =5;i>0;i--) { System.out.println(Thread.currentThread().getName()+"--i" +i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } }
关于 sleep() 和 wait() 不多讲了直接抄一篇博客的内容:http://blog.csdn.net/zidan_2011/article/details/7276468
这两者的施加者是有本质区别的.
sleep()是让某个线程暂停运行一段时间,其控制范围是由当前线程决定,也就是说,在线程里面决定.好比如说,我要做的事情是 "点火->烧水->煮面",而当我点完火之后我不立即烧水,我要休息一段时间再烧.对于运行的主动权是由我的流程来控制.
而wait(),首先,这是由某个确定的对象来调用的,将这个对象理解成一个传话的人,当这个人在某个线程里面说"暂停!",也是 thisOBJ.wait(),这里的暂停是阻塞,还是"点火->烧水->煮饭",thisOBJ就好比一个监督我的人站在我旁边,本来该线 程应该执行1后执行2,再执行3,而在2处被那个对象喊暂停,那么我就会一直等在这里而不执行3,但正个流程并没有结束,我一直想去煮饭,但还没被允许, 直到那个对象在某个地方说"通知暂停的线程启动!",也就是thisOBJ.notify()的时候,那么我就可以煮饭了,这个被暂停的线程就会从暂停处 继续执行.
其实两者都可以让线程暂停一段时间,但是本质的区别是一个线程的运行状态控制,一个是线程之间的通讯的问题
在Java.lang.Thread类中,提供了sleep(),
而java.lang.Object类中提供了wait(), notify()和notifyAll()方法来操作线程
sleep()可以将一个线程睡眠,参数可以指定一个时间。
而wait()可以将一个线程挂起,直到超时或者该线程被唤醒。
wait有两种形式wait()和wait(milliseconds).
sleep和wait的区别有:
1,这两个方法来自不同的类分别是Thread和Object
2,最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。
3,wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
任何地方使用
synchronized(x){
x.notify()
//或者wait()
}
4,sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
java 线程详解