Coin163

首页 > JAVA多线程————一篇文章让你彻底征服多线程开发

JAVA多线程————一篇文章让你彻底征服多线程开发

2021腾讯云限时秒杀,爆款1核2G云服务器298元/3年!(领取2860元代金券),
地址https://cloud.tencent.com/act/cps/redirect?redirect=1062

2021阿里云最低价产品入口+领取代金券(老用户3折起),
入口地址https://www.aliyun.com/minisite/goods

相关推荐:Java多线程——阻塞队列和并发集合

原文链接: http://blog.sina.com.cn/s/blog_616e189f0100rw7x.html Java多线程 阻塞队列和并发集合 本章主要探讨在多线程程序中与集合相关的内容。在多线程程序中,如果使用普通集合往往会造成数据错误,甚至造成程序崩溃。Java为多线程专门提供了特有的线程

线程生命周期

线程是一个进程中的执行场景,一个进程可以启动多个线程

多线程不是为了提高执行速度,而是提高应用程序的使用率.

线程和线程共享”堆内存和方法区内存”.栈内存是独立的,一个线程一个栈.

可以给现实世界中的人类一种错觉 : 感觉多线程在同时并发执行.

相关推荐:java多线程(一)线程状态与创建线程

一、几个基本概念的区分 1.进程与程序的区分 程序 进程 包含代码部分、数据部分 包含代码部分、数据部分、进程控制块 顺序执行 并发执行 独占资源 共享资源 同步的 异步的 静态的 动态的 (本质区别) 2.线程与进程的关系 相同:线程是轻量级的进程,一个进程

很多人都对其中的一些概念不够明确,如同步、并发等等,让我们先建立一个数据字典,以免产生误会。

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

    线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果,如不加事务的转账代码:

 void transferMoney(User from, User to, float amount){

   to.setMoney(to.getBalance() + amount);

   from.setMoney(from.getBalance() - amount);
 }

同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。如上面的代码简单加入@synchronized关键字。在保证结果准确的同时,提高性能,才是优秀的程序。线程安全的优先级高于性能。

Java命令会启动Java虚拟机,启动JVM,等于启动了一个应用程序,表示启动了一个进程,该进程会自动启动一个”主线程”,

然后主线程去调用某个类的main()方法,所以main()方法运行在主线程中.

http://upload-images.jianshu.io/upload_images/1689841-383f7101e6588094.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240&_=5479442

线程的调度与控制

线程的调度模型分为: 分时调度模型抢占式调度模型,Java使用抢占式调度模型

  • 分时调度模型: 所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
  • 抢占式调度模型: 优先让优先级高的线程使用CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些.
public class ThreadTest {

    public static void main(String[] args) {
        ThreadTest1();
        ThreadTest2();
        ThreadTest3();
        ThreadTest4();
        ThreadTest5();
    }

    /** * 三个方法: 获取当前线程对象:Thread.currentThread(); 给线程起名: t1.setName("t1"); 获取线程的名字: t.getName(); */
    private static void ThreadTest1() {
        Thread t = Thread.currentThread();// t保存的内存地址指向的线程为"主线程"
        System.out.println(t.getId());
        Thread t1 = new Thread(new Processor1());
        // 给线程起名
        t1.setName("t1");
        t1.start();
        Thread t2 = new Thread(new Processor1());
        t2.setName("t2");
        t2.start();
    }

    /** * 线程优先级高的获取的CPU时间片相对多一些 优先级: 1-10 最低: 1 最高: 10 默认: 5 */
    private static void ThreadTest2() {
        Thread t1 = new Processor2();
        Thread t2 = new Processor2();
        t1.setName("t1");
        t2.setName("t2");

        System.out.println(t1.getPriority());
        System.out.println(t2.getPriority());
        t1.setPriority(1);
        t2.setPriority(10);

        t1.start();
        t2.start();
    }

    /** * 1.Thread.sleep(毫秒); 2.sleep方法是一个静态方法 3.该方法的作用: 阻塞当前线程,腾出CPU,让给其它线程 */
    private static void ThreadTest3() {
        Thread t = new Thread(new Processor3());
        t.start();
        for (int i = 0; i < 11; i++) {
            System.out.println(Thread.currentThread().getName() + "========>" + i);
            try {
                t.sleep(5000);// 等同于Thread.sleep(5000);阻塞的还是当前线程,和t线程无关.
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /** * 某线程正在休眠,如何打断它的休眠 以下方式依靠的是异常处理机制 */
    private static void ThreadTest4() {
        try {
            Thread t = new Thread(new Processor4());
            t.start();
            Thread.sleep(5000);// 睡5s
            t.interrupt();// 打断Thread的睡眠
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /** * 如何正确的更好的终止一个正在执行的线程 需求:线程启动5s之后终止. */
    private static void ThreadTest5() {
        Processor5 p = new Processor5();
        Thread t = new Thread(p);
        t.start();
        // 5s之后终止
        try {
            Thread.sleep(5000);
            p.isRun = false;
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

class Processor1 implements Runnable {

    @Override
    public void run() {
        Thread t = Thread.currentThread();// t保存的内存地址指向的线程为"t1线程对象"
        System.out.println(t.getName());
        System.out.println(t.getId());

    }
}

class Processor2 extends Thread {

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            System.out.println(Thread.currentThread().getName() + "----------->" + i);
        }

    }
}

class Processor3 implements Runnable {

    /** * Thread中的run方法不能抛出异常,所以重写runn方法之后,在run方法的声明位置上不能使用throws 所以run方法中的异常只能try...catch... */
    @Override
    public void run() {
        for (int i = 0; i < 11; i++) {
            System.out.println(Thread.currentThread().getName() + "========>" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

class Processor4 implements Runnable {

    @Override
    public void run() {
        try {
            Thread.sleep(1000000000);
            System.out.println("能否执行这里");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 11; i++) {
            System.out.println(Thread.currentThread().getName() + "========>" + i);
        }
    }
}

class Processor5 implements Runnable {

    boolean isRun = true;

    @Override
    public void run() {
        for (int i = 0; i < 11; i++) {
            if (isRun) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "========>" + i);
            }
        }
    }
}

synchronized

  • 异步编程模型 : t1线程执行t1的,t2线程执行t2的,两个线程之间谁也不等谁.
  • 同步编程模型 : t1线程和t2线程执行,t2线程必须等t1线程执行结束之后,t2线程才能执行,这是同步编程模型.
  • 什么时候要用同步呢?为什么要引入线程同步呢?
  • 1.为了数据的安全,尽管应用程序的使用率降低,但是为了保证数据是安全的,必须加入线程同步机制.
  • 线程同步机制使程序变成了(等同)单线程.
  • 2.什么条件下要使用线程同步?
  • 第一: 必须是多线程环境
  • 第二: 多线程环境共享同一个数据.
  • 第三: 共享的数据涉及到修改操作.
public class SynchronizedTest {
    public static void main(String[] args) {
        SynchronizeTest1();
    }

    private static void SynchronizeTest1() {
        Account account=new Account("Actno-001",5000.0);
        Thread t1=new Thread(new Processor(account));
        Thread t2=new Thread(new Processor(account));
        t1.start();
        t2.start();
    }

}
/** * 取款线程 */
class Processor implements Runnable{
    Account act;
    Processor(Account act){
        this.act=act;
    }
    @Override
    public void run() {
        act.withdraw(1000.0);
        System.out.println("取款1000.0成功,余额: "+act.getBalance());
    }

}
class Account {

    private String actno;
    private double balance;

    public Account() {
        super();
    }

    public Account(String actno, double balance) {
        super();
        this.actno = actno;
        this.balance = balance;
    }

    public String getActno() {
        return actno;
    }

    public void setActno(String actno) {
        this.actno = actno;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    /** * 对外提供一个取款的方法 对当前账户进行取款操作 */
    public void withdraw(double money) {
        //把需要同步的代码,放到同步语句块中.
        //遇到synchronized就找锁,找到就执行,找不到就等
        /** * 原理: t1线程和t2线程 * t1线程执行到此处,遇到了synchronized关键字,就会去找this的对象锁, * 如果找到this对象锁,则进入同步语句块中执行程序,当同步语句块中的代码执行结束之后, * t1线程归还this的对象锁. * * 在t1线程执行同步语句块的过程中,如果t2线程也过来执行以下代码,也遇到synchronized关键字, * 所以也去找this对象锁,但是该对象锁被t1线程持有,只能在这等待this对象的归还. * * synchronized关键字添加到成员方法上,线程拿走的也是this的对象锁. * */
        synchronized (this) {
            double after = balance - money;
            try {
                //延迟
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //更新
            this.setBalance(after);
        }
    }
}
public class SynchronizedTest2 {
    public static void main(String[] args) throws InterruptedException {
        MyClass mc1=new MyClass();
        MyClass mc2=new MyClass();
        Thread t1=new Thread(new Runnable1(mc1));
        Thread t2=new Thread(new Runnable1(mc2));
        t1.setName("t1");
        t2.setName("t2");

        t1.start();
        //延迟,保证t1先执行
        Thread.sleep(1000);
        t2.start();
    }
}
class Runnable1 implements Runnable{
    MyClass mc;
    Runnable1(MyClass mc){
        this.mc=mc;
    }
    @Override
    public void run() {
        if("t1".equals(Thread.currentThread().getName())){
            MyClass.m1();//因为是静态方法,用的还是类锁,和对象锁无关
        }
        if("t2".equals(Thread.currentThread().getName())){
            MyClass.m2();
        }
    }
}
class MyClass{
    //synchronized添加到静态方法上,线程执行此方法的时候会找类锁,类锁只有一把
    public synchronized static void m1(){
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("m1()............");
    }
    /** * m2()不会等m1结束,因为该方法没有被synchronized修饰 */
// public static void m2(){
// System.out.println("m2()........");
// }
    /** * m2方法等m1结束之后才能执行,该方法有synchronized * 线程执行该方法需要"类锁",而类锁只有一个. */
    public synchronized static void m2(){
        System.out.println("m2()........");
    }
}

死锁

public class DeadLock {

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

class T1 implements Runnable {

    Object o1;
    Object o2;

    T1(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }

    @Override
    public void run() {
        synchronized (o1) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o2) {

            }
        }
    }
}

class T2 implements Runnable {

    Object o1;
    Object o2;

    T2(Object o1, Object o2) {
        this.o1 = o1;
        this.o2 = o2;
    }

    @Override
    public void run() {
        synchronized (o2) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o1) {

            }
        }
    }
}

守护线程

  • 其它所有的用户线程结束,则守护线程退出!
  • 守护线程一般都是无限执行的.
public class DaemonThread {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable2());
        t1.setName("t1");
        // 将t1这个用户线程修改成守护线程.
        t1.setDaemon(true);
        t1.start();
        // 主线程
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + "----->" + i);
            Thread.sleep(1000);
        }
    }
}

class Runnable2 implements Runnable {

    @Override
    public void run() {
        int i = 0;
        while (true) {
            i++;
            System.out.println(Thread.currentThread().getName() + "-------->" + i);
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Timer.schedule()

/** * 关于定时器的应用 作用: 每隔一段固定的时间执行一段代码 */
public class TimerTest {

    public static void main(String[] args) throws ParseException {
        // 1.创建定时器
        Timer t = new Timer();
        // 2.指定定时任务
        t.schedule(new LogTimerTask(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").parse("2017-06-29 14:24:00 000"), 10 * 1000);
    }
}

// 指定任务
class LogTimerTask extends TimerTask {

    @Override
    public void run() {
        System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
    }
}

原文

线程生命周期 线程的调度与控制 synchronized 死锁 守护线程 Timerschedule 线程生命周期 线程是一个进程中的执行场景,一个进程可以启动多个线程 多线程不是为了提高执行速度,而是提高应用程序

------分隔线----------------------------