Java 线程宝典

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 线程宝典相关的知识,希望对你有一定的参考价值。

此文 为垃圾文 本人复习用的 emmm

  • 多线程:指的是这个程序(一个进程)运行时产生了不止一个线程
  • 并行与并发:
    • 并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
    • 并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。

  进程和线程的区分

 

  第一种实现方式:通过继承Thread类来实现的 线程

    摘要:

  技术分享

code:

package com.java.Thread;

public class MyThread {
    public static void main(String[] args){
        Apple a1 = new Apple("坏蛋");
            a1.start();
        Apple a2 = new Apple("好人");
            a2.start();
    }
}
class Apple extends Thread{
    private String name;

    public  Apple(String name){
        this.name = name;
    }

    public void run(){
        for (int i = 1; i < 10; i++){
            System.out.println(name+""+i);
        }
    }

}

每一个线程从的它的创建到销毁都有一个状态 如下是线程的各种状态:

技术分享

线程的四种状态

 

技术分享

然后实现现成的 第二种方式 实现 Runnable接口

  技术分享

code如下:

package cn.java.thread;

public class RunnableDemo {

    public static void main(String[] args) {
        Test t1 = new Test("haoren");
        Test t2 = new Test("hairen");
        Thread th1 = new Thread(t1);
        Thread th2 = new Thread(t2);
        th1.start();
        th2.start();
    }

}

class Test implements Runnable{
    private String name;
    
    public  Test(String name){
        this.name = name;
    }
    
    public void run(){
        for(int i=0;i<10;i++){
            System.out.println(name+":"+i);
        }
    }
}

  Thread和Runnable的关系

          1.Thread是Ruuable的之类

     2.实际上Thread和Runable的关系 跟代理设计模式很像,  这里的Thread就是代理类。我们自己所实现的类才是real。

   Thread和Runnable的区别

     Runable可以共享数据 

code如下:

package cn.java.thread;

public class ShareDemo {
    public static void main(String[] args) {
        Tickets t1 = new Tickets();
        
        Thread th1 = new Thread(t1);
        Thread th2 = new Thread(t1);
        th1.start();
        th2.start();
        
        
    }

}

class Tickets implements Runnable{
    private int ticket = 5;
    
    public void run(){
        for(int i=0;i<5;i++){
            if(ticket>0)
            System.out.print(ticket--);
            
        }
    }
}

然后 我说说这里面的 一个叫做jojn()的东东 网上各种帖子众说纷纭 而对他的理解就是 4个字  强制执行 做一个简单的验证吧.

package com.java.Thread;

public class MyJoin {
    public static void main(String[] ARGS){
        MyThread2 mt1 = new MyThread2();
        mt1.setName("线程1");
        mt1.start();
        for (int i = 0; i < 10; i++) {
            if(i==5){
                try {
                    mt1.join();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

            }
            System.out.println(i);
        }


    }
}
class MyThread2 extends Thread {
    /*public MyThread(String string) {
    }*/

    public void run() {
        int i = 0;
        while (i < 10) {
            System.out.println(Thread.currentThread().getName());
            i++;
        }


    }
}

运行结果如下

技术分享

然后在 说说 interrupt 中断  一个线程意味着在该线程完成任务之前停止其正在进行的一切,有效地中止其当前的操作。线程是死亡、还是等待新的任务或是继续运行至下一步,就取决于这个程序。虽然初次看来它可能显得简单,但是,你必须进行一些预警以实现期望的结果。你最好还是牢记以下的几点告诫。 

    首先,忘掉Thread.stop方法。虽然它确实停止了一个正在运行的线程,然而,这种方法是不安全也是不受提倡的,这意味着,在未来的Java版本中,它将不复存在。 

    一些轻率的家伙可能被另一种方法Thread.interrupt所迷惑。尽管,其名称似乎在暗示着什么,然而,这种方法并不会中断一个正在运行的线程(待会将进一步说明),正如Listing A中描述的那样。它创建了一个线程,并且试图使用Thread.interrupt方法停止该线程。Thread.sleep()方法的调用,为线程的初始化和中止提供了充裕的时间。线程本身并不参与任何有用的操作。 

code如下:

package com.java.Thread;

public class MyInterrupt {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        MyThread3 mt = new MyThread3();
        mt.start();

        try {
            Thread.sleep(2000);
            System.out.println("main休眠结束");
        } catch (InterruptedException e) {

            e.printStackTrace();
        }

        mt.interrupt();

    }
}

class MyThread3 extends Thread{
    public void run(){
        System.out.println("进入run");
        try {
            Thread.sleep(8000);

        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            //e.printStackTrace();
            System.out.println("run休眠结束!!!");//sleep被中断会抛出InterruptedException 推荐直接抛出 不要捕获
        }
        System.out.println("run运行结束");
    }

}

然后来到线程礼让  俗话点说 就是 线程A是个君子 看见线程B是个 美女就干什么都让着她 让她先过..

code如下:

package com.java.Thread;
//线程礼让
public class MyYield {
    public static void main(String[] ARGS){
        MyThred m1 = new MyThred();
            Thread t1 = new Thread(m1,"李四");
            Thread t2 = new Thread(m1,"王五");
            t1.start();
            t2.start();
    }
}
class MyThred implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 5; i++){
            System.out.println(Thread.currentThread().getName()+"运行>>>>>" + i);
            if (i==2) {
                System.out.println("线程礼让");
                Thread.currentThread().yield();
            }
        }
    }
}

然后 来到  setdaenmo 后台线程设置

Java中线程分为两种类型:用户线程守护线程。通过Thread.setDaemon(false)设置为用户线程;通过Thread.setDaemon(true)设置为守护线程。如果不设置次属性,默认为用户线程。

用户线程和守护线程的区别:

1. 主线程结束后用户线程还会继续运行,JVM存活;主线程结束后守护线程和JVM的状态又下面第2条确定。

2.如果没有用户线程,都是守护线程,那么JVM结束(随之而来的是所有的一切烟消云散,包括所有的守护线程)。

code如下:

package com.java.Thread;

public class SetDaemon {
    public static void main(String[] ARGS){
        Persons p1 = new Persons();
            Thread th = new Thread(p1);
                th.setDaemon(true);//如果不加此语句就永远无法结束
        th.start();

    }
}
class Persons implements Runnable{

    @Override
    public void run() {
        while (true){
            System.out.println("哈哈哈哈哈哈sss");
        }
    }
}

 然后 设置线程的优先级别 这点要说说 高的不一定会优先执行.

这是定义表

技术分享

通过 setPriority方法来执行

技术分享

 来到重点中的重点  拿个小本本记住 线程安全 

  导致线程安全出现的原因:

技术分享

技术分享

所以 我们为了解决这个问题 推出了 同步 synchronized

  技术分享

然后同步又有两种模式 一种是同步代码块 另外一种是同步函数 这两种同步加锁的方式不一样 = =且看我细细道来

  先看看code

package cn.tread;

public class TicketDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Person2 p1 = new Person2("haoren");
        Thread t1 = new Thread(p1);
        Thread t2 = new Thread(p1);
        t1.start();
        t2.start();

    }

}

class Person2 implements Runnable {
    private String name;
    private int tickets = 5;

    public Person2(String name) {
        this.name = name;
    }
   //同步代码块 需要的锁是 任意对象~
    Object object1 = new Object();

    public void run() {

        for (int i = 0; i < 5; i++) {
            synchronized (object1) {//object1就是传说中的锁,要同步必须使用同一个锁
                if (tickets > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {

                        e.printStackTrace();
                    }

                    System.out.println(tickets--);
                }
            }
        }

    }
}

观察上面的代码  我们 有了一个总结 同步代码的锁可以是任意对象

 然后是同步的前提

技术分享

技术分享

同步的弊端

技术分享

 然后我们说说同步函数

 

package cn.java.thread;

/*
 证明同步函数用的是this这把锁
 */
public class Tickets1 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        /*
         * GetTickets gt1 = new GetTickets(); GetTickets gt2 = new GetTickets();
         * GetTickets gt3 = new GetTickets(); gt1.setName("窗口一");
         * gt2.setName("窗口二"); gt3.setName("窗口三"); gt1.start(); gt2.start();
         * gt3.start();
         */
        GetTickets2 gt = new GetTickets2();
        Thread th1 = new Thread(gt, "窗口一");
        Thread th2 = new Thread(gt, "窗口二");
        Thread th3 = new Thread(gt, "窗口三");
        th1.start();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        gt.flag = true;
        th2.start();
        th3.start();
    }

}

class GetTickets2 implements Runnable {

    private int tickets = 10;
    boolean flag = false;
    Object ob = new Object();
    public void run() {
        if (flag) {
            for (int i = 0; i < 10; i++) {
                //synchronized (ob) {//如果用ob就无法同步
                synchronized (this) {
                    if (tickets > 0) {
                        try {
                            Thread.sleep(500);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()
                                + "卖出" + (tickets--) + "号票"+":同步代码块");
                    }
                }
                
            }
            
        } else {
            for (int i = 0; i < 10; i++) {
                function();
                
            }

        }
    }

    public synchronized void function() {

        if (tickets > 0) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "卖出"
                    + (tickets--) + "号票"+":同步函数");
            
        }
    }

}
/*
 * class GetTickets extends Thread{ //private static int tickets = 10; private
 * int tickets = 10; public void run(){
 * 
 * for (int i = 0; i < 10; i++) { if(tickets>0){
 * System.out.println(Thread.currentThread().getName()+"卖出"+(tickets--)+"号票"); }
 * } } }
 */

通过 观察我们不难发现 

技术分享

 余下的我在下一个分P写...






以上是关于Java 线程宝典的主要内容,如果未能解决你的问题,请参考以下文章

Java 线程宝典

[Interview]Java 面试宝典系列之 Java 多线程

Java 面试宝典!并发编程 71 道题及答案全送上!

Java核心面试宝典Day14“线程池”高频面试题总结!✊✊✊

Java核心面试宝典Day14“线程池”高频面试题总结!✊✊✊

Java面试宝典,三面蚂蚁金服成功拿到offer