转自:https://blog.csdn.net/dataiyangu/article/details/86226835#

什么是线程?
线程的基本操作
线程的基本操作
新建线程
调用run的一种方式
调用run另的一种方式
终止线程 **(弃用)**
中断线程
挂起(suspend)和继续执行(resume)线程 ** (弃用)**
等待线程结束(join)和谦让(yeild)
yeild
join
守护线程
线程优先级
基本的线程同步操作
synchronized ** (注意拿到的东西必须是同一个)**
Object.wait() Obejct.notify()
什么是线程?
线程是进程内的执行单元。
每个进程中有若干个线程,进程的切换是非常重量型的,所线程可以作为较为广泛的并发涉及

java中调动了线程会映射到操作系统中,两者是等价的

线程的基本操作

线程的基本操作
新建线程
Thread t1=new Thread(); t1.start();
每一个线程都是runable接口的实现
start方法就能把这个线程跑起来,开启一个线程
在一个新的操作系统的线程上面调用run方法
Thread t1=new Thread(); t1.run();
不能开启线程

调用run方法和调用start方法做的事情是一样的 ,但是run并不会开启新的线程而是在调用run的当前的这个线程当中执行这个操作,只有使用的start方法才是在真的一个新的线程当中执行run中的事情

Thread.run()的实现 target 是Runnable接口(run是runnable接口中的一个方法)
run方法源码

private Runnable target;
public void run() {
if (target != null) {
target.run();
} }

Thread 的init方法:

public Thread(){
init(null,null,"Thread-"+nextThreadNum(),0)
//init方法是在new对象的时候自动执行的
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}

调用run的一种方式
这里的target本身就是传的null,所以就可以把run方法重载,把我们的方法写进去

Thread t1=new Thread(){
@Override
public void run(){
System.out.println("Hello, I am t1");
} };
t1.start();

调用run另的一种方式
将target传到init方法中,来运行run方法。如下面CreateThread3(一个runnable的实例),这里不需要重载run方法,t1.start()的时候会自动去调用target.run。

Thread t1=new Thread(new CreateThread3()); t1.start();
1
终止线程 (弃用)
– Thread.stop() 不推荐使用。它会释放所有monitor
记录1:ID=1,NAME=小明
记录2:ID=2,NAME=小王

如上图,在读和写的时候加入锁,当写完id,正要写name的时候,stop掉了thread,这个时候,会把锁释放掉,导致将id写了进去,name没有写进去,出现数据的不一致。

中断线程
public void Thread.interrupt() // 中断线程
public boolean Thread.isInterrupted() // 判断是否被中断
public static boolean Thread.interrupted() // 判断是否被中断,并清除当前中断状态

public void run(){ while(true){
Thread.yield();
} }
t1.interrupt();

t1.interrupt();我只是告诉线程你应该终止了,对线程没有任何的影响,还是在跑着的。

public void run(){ while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Interruted!");
break;
}
Thread.yield();
} }

通过Thread.currentThread().isInterrupted()判断当前的线程是不是被interrupt(),告知过要中断,是的话就break出while循环,同时终止run方法,也就自动终止了thread,这里不会出现数据的不一致,因为是在Thread.yield();(下一次数据处理之前)对线程进行终止的。
拓展

public static native void sleep(long millis) throws InterruptedException

public void run(){ while(true){
if(Thread.currentThread().isInterrupted()){
System.out.println("Interruted!");
break; }
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Interruted When Sleep");
//设置中断状态,抛出异常后会清除中断标记位
Thread.currentThread().interrupt();
}
Thread.yield();
}
}

sleep即休眠方法。为什么休眠方法需要抛出 throws InterruptedException异常呢?
如果我在休眠的过程中,线程出现了isInterrupted(中断)的请求怎么办?这个时候如果sleep会抛出一个异常,同时自动清除interrupt()设置的标志位,所以需要在抛出的异常中添加Thread.currentThread().interrupt();以保证能够被上面的Thread.currentThread().isInterrupted()检测到从而中断线程。

挂起(suspend)和继续执行(resume)线程 (弃用)
suspend()不会释放锁 ,发现suspend之后现场称还是runnable的状态,当然不代表所有的挂起后线程会runnable。
如果加锁发生在resume()之前 ,则死锁发生

如上图,线程1挂起可,这个时候没有释放锁,希望通过线程2来resume锁,但是线程2的resume可能意外的发生在suspend之前,这个时候线程1将会永远的挂,其他的锁(如上图线程3)将会无线等待线程1拿到的锁。

等待线程结束(join)和谦让(yeild)
yeild
当前线程优先级不是特别高,希望其他线程有机会争夺cpu时间,所以讲当前占用的cpu事件释放掉,使得其他的线程有更多的机会继续往下执行,但是下次还是有机会拿到cpu时间,不代表永远的让出去。

join
线程a希望知道线程b什么时候结束,因为需要在线程b结束的时候来立马做某些事情。

public class JoinMain {
public volatile static int i=0;
public static class AddThread extends Thread{
@Override public void run() {
for(i=0;i<10000000;i++); }
}
public static void main(String[] args) throws InterruptedException {
AddThread at=new AddThread();
at.start();
at.join();
System.out.println(i);
} }

如上面的代码,希望在主线程中加入at方法,在at方法执行完毕之后再执行System.out.println(i);这句话。

join(有时间和没时间的,如果有无参数就是无限等待,有参数,就是等待一段时间如果还没有结束就继续往下执行,我等不起。)
join的本质

while (isAlive()) {
wait(0);
}

如果线程是isalive(没死掉的),就无线等待,直到线程执行完毕后, 系统会调用 notifyAll(),注意 ** 不要在Thread实例上使用 wait()和notify()方法

守护线程
在后台默默地完成一些系统性的服务,比如垃圾回收线程、JIT线程就可以理解为守护线程
当一个Java应用内,只有守护线程时,Java虚拟机就会自然退出
Thread t=new DaemonT(); t.setDaemon(true); t.start();
举例子:

psvm(){
Thread t =new DeamonT();
t.setDaemon(true);
t.start();
}

会发现,刚启动程序,就自动停掉了。

线程优先级
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;

Thread high=new HightPriority(); LowPriority low=new LowPriority();
high.setPriority(Thread.MAX_PRIORITY);
low.setPriority(Thread.MIN_PRIORITY);
low.start();
high.start();

low的优先级比high高
高优先级的线程更容易再竞争中获胜

基本的线程同步操作
synchronized (注意拿到的东西必须是同一个)
这个关键字是java内置的,所有的实现是在虚拟机内部做的,包括拿锁、线程挂起、挂起之前做的优化等待等。
– 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定对象的锁。

public class AccoutingSync2 implements Runnable{
static AccoutingSync2 instance = new AccoutingSync2();
static int i =0 ;
public void run() {
for (int i = 0; i < 100000; i++) {
synchronized (instance) {
i++;
}
}
}

public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}

– 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。

public class AccoutingSync2 implements Runnable{
// static AccoutingSync2 instance = new AccoutingSync2();
static int i =0 ;
public synchronized void increase(){
i++;
}
public void run() {
for (int i = 0; i < 100000; i++) {
increase();
}
}

public static void main(String[] args) throws InterruptedException {
//Thread t1 = new Thread(new AccoutingSync2());
//Thread t2 = new Thread(new AccoutingSync2());
AccoutingSync2 accoutingSync2 = new AccoutingSync2();
Thread t1 = new Thread(accoutingSync2);
Thread t2 = new Thread(accoutingSync2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}

注意上面的mian方法的两行注释,如果new两次AccoutingSync2,是两个对象,这样作用于方法上的锁,并不是一个实例对象,是不对的,必须是一个实例对象才能用这种方法。

– 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。

public class AccoutingSync2 implements Runnable{
// static AccoutingSync2 instance = new AccoutingSync2();
static int i =0 ;
public synchronized void increase(){
i++;
}
public void run() {
for (int i = 0; i < 100000; i++) {
increase();
}
}

public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new AccoutingSync2());
Thread t2 = new Thread(new AccoutingSync2());
//AccoutingSync2 accoutingSync2 = new AccoutingSync2();
//Thread t1 = new Thread(accoutingSync2);
//Thread t2 = new Thread(accoutingSync2);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(i);
}
}

将上面的代码微整,将synchronized修饰的方法变为static的,这个方法是属于类的,此时main函数中的Thread可以通过new AccoutingSync2()的方式来new。

Object.wait() Obejct.notify()
Object.wait()线程等待在当前对象上
Obejct.notify()通知等待在这个对象上的wait()函数返回

Object.wait()必须要先获得当前object的锁才能去调用wait方法
Obejct.notify()也必须获得当前的object
注意:共有的锁必须在执行到synchronized代码之后才会被完全的释放

import java.sql.SQLOutput;

public class Test {
public static Object object = new Object();
public static class T1 extends Thread{
public void run (){
synchronized (object){
System.out.println(System.currentTimeMillis()+":T1 start!");
try{
System.out.println(System.currentTimeMillis()+":T1 wait for object ");
object.wait();
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+"T1 end");
}
}
}
public static class T2 extends Thread{
public void run(){
synchronized (object){
System.out.println(System.currentTimeMillis()+":T2 start! notify one thread!");
object.notify();
System.out.println(System.currentTimeMillis()+"T2 end");
try{
Thread.sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}

public static void main(String[] args) {
Thread t1 = new T1();
Thread t2 = new T2();
t1.start();
t2.start();
}
}

注意上面的代码中wait和notify两个方法执行之前都需要获得object这个锁,包括wait的继续向下也需要这个锁 比如,打印出System.out.println(System.currentTimeMillis()+"T2 end");这句话之后会不会立即打印出System.out.println(System.currentTimeMillis()+"T1 end");? 答:不会因为wait和notify都在共用object这个锁,在输出System.out.println(System.currentTimeMillis()+"T2 end");这句话的时候还没有完全释放object对象,简单来说就是代码还在synchronized (object){}这个代码块中,所以只能在等待sleep2000之后再重新回来执行T1 end的操作。

具体停留两秒的效果还需要读者自己尝试

import org.omg.PortableServer.THREAD_POLICY_ID;

import java.sql.SQLOutput;

public class Test {
public static Object object = new Object();
public static class T1 extends Thread{
public void run (){
synchronized (object){
System.out.println(System.currentTimeMillis()+":T1 start!");
try{
System.out.println(System.currentTimeMillis()+":T1 wait for object ");
object.wait();
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+"T1 end");
}
}
}
public static class T2 extends Thread{
public void run(){
synchronized (object){
System.out.println(System.currentTimeMillis()+":T2 start! notify one thread!");
object.notifyAll();
System.out.println(System.currentTimeMillis()+"T2 end");
try{
Thread.sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}

public static void main(String[] args) throws InterruptedException {
Thread t1 = new T1();
Thread t2 = new T2();
Thread t3 = new T1();
t1.start();
t3.start();
Thread.sleep(3000);
t2.start();
}
}

描述:
可以看到上面的代码中

object.wait();
Thread.sleep(1000);
1
2
这里在wait方法后进行了sleep,创建了两个t1,将两个释放都释放的时候,中间会间断一秒,同时印证了上面必须要让程序执行到synchronize代码块外面之后再进行下一步。

具体停留效果需要读者亲自尝试。

Java高并发程序设计学习笔记(二):多线程基础的更多相关文章

  1. Java高并发程序设计学习笔记(十一):Jetty分析

    转自:https://blog.csdn.net/dataiyangu/article/details/87894253 new Server()初始化线程池QueuedThreadPoolexecu ...

  2. Java高并发程序设计学习笔记(十):并发调试和JDK8新特性

    转自:https://blog.csdn.net/dataiyangu/article/details/87631574 多线程调试的方法使用Eclipse进行多线程调试线程dump及分析分析死锁案例 ...

  3. Java高并发程序设计学习笔记(七):并行设计模式

    转自:https://blog.csdn.net/dataiyangu/article/details/87123586 什么是设计模式架构模式设计模式代码模式(成例 Idiom)单例模式普通单例假如 ...

  4. Java高并发程序设计学习笔记(六):JDK并发包(线程池的基本使用、ForkJoin)

    转自:https://blog.csdn.net/dataiyangu/article/details/86573222 1. 线程池的基本使用1.1. 为什么需要线程池1.2. JDK为我们提供了哪 ...

  5. Java高并发程序设计学习笔记(三):Java内存模型和线程安全

    转自:https://blog.csdn.net/dataiyangu/article/details/86412704 原子性有序性可见性– 编译器优化– 硬件优化(如写吸收,批操作)Java虚拟机 ...

  6. Java高并发程序设计学习笔记(一):并行简介以及重要概念

    转自:https://blog.csdn.net/dataiyangu/article/details/86211544#_28 文章目录为什么需要并行?反对意见大势所趋几个重要的概念同步(synch ...

  7. Java高并发程序设计学习笔记(九):锁的优化和注意事项

    转自:https://blog.csdn.net/dataiyangu/article/details/87612028 锁优化的思路和方法减少锁持有时间减小锁粒度锁分离锁粗化举个栗子举个栗子锁消除虚 ...

  8. Java高并发程序设计学习笔记(八):NIO和AIO

    转自:https://blog.csdn.net/dataiyangu/article/details/87214773 什么是NIOBuffer && ChannelBuffer举个 ...

  9. Java高并发程序设计学习笔记(四):无锁

    转自:https://blog.csdn.net/dataiyangu/article/details/86440836#1__3 1. 无锁类的原理详解简介:1.1. CAS1.2. CPU指令2. ...

随机推荐

  1. Android res之shape

    xml控件配置属性 android:background="@drawable/shape" 标签 corners ----------圆角gradient ----------渐 ...

  2. LC 683. K Empty Slots 【lock,hard】

    There is a garden with N slots. In each slot, there is a flower. The N flowers will bloom one by one ...

  3. 数据解析框架之Gson

    GSON是由Google提供的,用于JAVA对象与JSON字符串之间互相转换的一个解决方案.用处很多,比如在前后台通讯中,前台先将java对象转化成JSON,然后将JSON传输给后台交由后台处理——相 ...

  4. Eclipse使用git发布项目到github

    因为一直都在使用svn,今天尝试了下git,记录下来既是方便自己以后查看,也是分享一些经验! 废话不多说,撸起袖子就是干!!! 1.选中要上传的项目右键 2.选中git 3.在图上打钩,点击所要上传的 ...

  5. linux 基础 文件操作

    cat -A /etc/passwdnl -ba passwd cat -A man_db.conf more man_db.conf less man_db.conf head -n 5 /var/ ...

  6. 反向代理,负载均衡——nginx理论

    nginx是什么? nginx是一个强大的web服务器软件,用于处理高并发的http请求和作为反向代理服务器做负载均衡.具有高性能.轻量级.内存消耗少,强大的负载均衡能力等优势.  nginx架构? ...

  7. gulp4.0配置

    var gulp = require('gulp'); var rename = require('gulp-rename');//重命名 var uglify=require('gulp-uglif ...

  8. Cisco路由器的dhcp服务的配置的命令

    Router(config)#IP DHCP POOL Jason Router(dhcp-config)#net 172.16.10.0 255.255.255.0 Router(dhcp-conf ...

  9. 【Python开发】Lambda表达式使用

    lambda只是一个表达式,函数体比def简单很多. lambda的主体是一个表达式,而不是一个代码块.仅仅能在lambda表达式中封装有限的逻辑进去. lambda表达式是起到一个函数速写的作用.允 ...

  10. icon.css

    .icon-blank{ background:url('icons/blank.gif') no-repeat; } .icon-add{ background:url('icons/edit_ad ...