美文网首页
《实战Java高并发程序设计》学习记录2

《实战Java高并发程序设计》学习记录2

作者: 少寨主的互联网洞察 | 来源:发表于2018-11-09 15:21 被阅读0次

什么是线程

线程是进程内的执行单元

线程的基本操作

image.png

新建线程

image.png

为什么呢?看看源码


image.png
image.png
image.png

停止线程

Thread.stop() 不推荐使用。它会释放所有monitor
示例:


image.png

线程中断(怎么优雅的让一个线程停止运作)

示例1:如果仅仅是下面这样的方式

image.png

线程并不会终止,虽然已经通知它中断运行了,但是没有作相应的判断标志位,所以线程并不会去理会这个中断通知

示例2:(优雅的方式)

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

示例三

image.png

挂起( suspend)和继续执行( resume)线程

– suspend()不会释放锁
– 如果加锁发生在resume()之前 ,则死锁发生

image.png
  • 为什么?看看源码
@Deprecated
    public final void suspend() {
        checkAccess();
        suspend0();
    }

解释怎么说?

@deprecated This method has been deprecated, as it is
* inherently deadlock-prone. If the target thread holds a lock on the
* monitor protecting a critical system resource when it is suspended, no
* thread can access this resource until the target thread is resumed. If
* the thread that would resume the target thread attempts to lock this
* monitor prior to calling <code>resume</code>, deadlock results. Such
* deadlocks typically manifest themselves as "frozen" processes.

代码实现

package someTest;

public class BadSuspend {
    public static Object u=new Object();
    static ChangeObjectThread t1=new ChangeObjectThread("t1");
    static ChangeObjectThread t2=new ChangeObjectThread("t2");
    
    public static class ChangeObjectThread extends Thread{
        public ChangeObjectThread(String name) {
            super.setName(name);
        }
        @Override
        public void run() {
            synchronized (u) {
                System.out.println("in "+getName());
                Thread.currentThread().suspend();
            }
        }
    }
    public static void main(String[] args) throws InterruptedException {
        t1.start();
        Thread.sleep(100);
        t2.start();
        t1.resume();
        t2.resume();
        t1.join();
        t2.join();
    }
}

上面这个程序就会卡在主程序里面出不来,因为t2的resume()方法先执行,suspend()方法后执行,导致t2一直卡在suspend挂起状态出不来,所以就卡住了。

等待线程结束( join)和谦让(yeild)

  • yield:我把cpu让出来,大家一起竞争,给大家一个竞争的机会,当然自己还是有可能再次获得cpu的执行权
  • join:
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.join();等待at这个线程先执行完,再往下走
join的本质:让所有等待当前线程的其他线程等待

join的本质
while (isAlive()) {
wait(0);
}
image.png

当然,等待的时间也是可以设置的,比如我想等待一段时间以后就不等了^^
建议:


image.png

源码里面直接说明,建议不要使用Thread对象实例的wait和notify方法,因为这些方法操作系统会进行调用,你调用了不保证达到理想的效果

守护线程

  • 在后台默默地完成一些系统性的服务,比如垃圾回收线程、 JIT线程就可以理解为守护线程
  • 当一个Java应用内,只有守护线程时, Java虚拟机就会自然退出
package someTest;

public class DaemonDemo {
    public static class DaemonT extends Thread{
        public void run() {
            while(true) {
                System.out.println("I am alive");
                try {
                    Thread.sleep(1000);
                }catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) {
        Thread t=new DaemonT();
        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;
image.png
  • 高优先级的线程更容易再竞争中获胜,概率问题,结果不保证

线程同步操作

  • synchronized

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

package someTest;

public class AccountingAsync implements Runnable{
    static AccountingAsync instance=new AccountingAsync();
    static int i=0;
    @Override
    public void run() {
        for(int j=0;j<10000;j++) {
            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);
    }
}

以上正确输出20000
根据synchronized修饰的位置不同,有不同的作用域,所以在使用锁的时候一定要注意用到合适的对象上,比如将这个关键字用在静态方法上,就相当于对类进行加锁,结果还是20000

package someTest;

public class AccountingAsync implements Runnable{
    static AccountingAsync instance=new AccountingAsync();
    static int i=0;
    public static synchronized void increase() {
        i++;
    }
    @Override
    public void run() {
        for(int j=0;j<10000;j++) {
            increase();
        }
    }
    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);
    }
}

Object.wait() Obejct.notify()

Object.wait():使线程等待在当前对象上
Obejct.notify():通知等待在当前对象上的线程

  • 注意事项:以上两个方法必须要在拿到对象监视器锁以后才能调用,没拿到以前是不能调用的,同时如果一个线程拿到了对象监视器锁,然后调用wait()方法就会释放当前对象的监视器锁,而notify方法不一样,不会立即释放,而是等它执行完了再释放

相关文章

网友评论

      本文标题:《实战Java高并发程序设计》学习记录2

      本文链接:https://www.haomeiwen.com/subject/juonxqtx.html