zoukankan      html  css  js  c++  java
  • java基础-多线程

     

    Java中的线程


    在Java中,“线程”指两件不同的事情:
    1、java.lang.Thread类的一个实例;

    2、线程的执行。

    java中要想实现多线程,有两种手段,一种是继续Thread类,另外一种是实现Runable接口.(但是其实本质上都是通过Thread实现的

    使用java.lang.Thread类或者java.lang.Runnable接口编写代码来定义、实例化和启动新线程。

     

    一个Thread类实例只是一个对象,像Java中的任何其他对象一样,具有变量和方法,生死于堆上。

     

    Java中,每个线程都有一个调用栈,即使不在程序中创建任何新的线程,线程也在后台运行着。

     

    一个Java应用总是从main()方法开始运行,mian()方法运行在一个线程内,它被称为主线程。

     

    一旦创建一个新的线程,就产生一个新的调用栈。

    下面来看看第一种Thread方法创建

     

    package Thread;
    
    public class Threadtest extends Thread{
        @Override
        public void run(){
            System.out.println("多线程的运行代码");
            for(int i=0;i<6;i++)
            {
                System.out.println("这是多线程的逻辑代码代替实现"+i);
            }
        }
    }
    package Thread;
    
    public class test {
        public static void main(String[] args) {
            Thread t0 = new Threadtest();
            t0.start();//启动
            System.out.println("---------");
            System.out.println("---------");
            System.out.println("---------");
        }
    }

     我们发现顺序不对!

    原因是main方法即主线程执行t0.start多线程后,相当于在main方法之外开启一个支流

    即t0.start()为一个分割线,在它之后的代码和run方法并行运行了就像两条支流。所以没有顺序,甚至多试几次还会出现--------------在中间等情况

     

     而这就是多线程的异步性

    。那么来看第二种创建方式过程(推荐)

    package Thread;
    
    public class TestRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println("Runnable多线程的运行代码");
            for(int i=0;i<6;i++)
            {
                System.out.println("这是Runnable多线程的逻辑代码代替实现"+i);
            }
        }
    }
    package Thread;
    
    public class test {
        public static void main(String[] args) {
    //        Thread t0 = new Threadtest();
    //        t0.start();//启动
            Thread t2 = new Thread(new TestRunnable()); //里面有一个Runnable对象
            t2.start();
            System.out.println("---------");
            System.out.println("---------");
            System.out.println("---------");
        }
    }

     当然Runnable不会这么简单

    再来看一下加名字的变化

    package Thread;
    
    public class TestRunnable implements Runnable {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName()+"Runnable多线程的运行代码");
            for(int i=0;i<6;i++)
            {
                System.out.println(Thread.currentThread().getName()+"这是Runnable多线程的逻辑代码代替实现"+i);
            }
        }
    }
    package Thread;
    
    public class test {
        public static void main(String[] args) {
    //        Thread t0 = new Threadtest();
    //        t0.start();//启动
            Thread t2 = new Thread(new TestRunnable(),"t-2");
            t2.start();
            Thread t3 = new Thread(new TestRunnable(),"t-3");
            t3.start();
            System.out.println("---------");
            System.out.println("---------");
            System.out.println("---------");
        }
    }

     以上两个就是创建线程的过程和方式

    1继承Thread类 重写run方法

    2实现Runnable接口   实现run方法(推荐)

    而实现run方法也好处更多

    1因为继承了Thread就不能继承其他父类,不能再继承,(java的单继承原则)

    2共享资源,多线程共享一个接口实现类的对象,可以多线程处理同一个资源。比如那一个count来计数

    看例子

     会发现count是共同的,并且还递增。

    看完了上面之后再来了解一下同步与死锁的应用,思考一个问题

    package ThreadTongbu;
    
    public class test {
        public static void main(String[] args) {
            //定义一个账户
            Account a = new Account();
    
            User u_weixin = new User(a,2000);
            User u_zhifubao = new User(a,2000);
    
            Thread weixin = new Thread(u_weixin,"微信");
            Thread zhifubao = new Thread(u_zhifubao,"支付宝");
            weixin.start();
            zhifubao.start();
        }
    }
    
    class Account{
        public static int money = 3000;
    
        public void drawing(int m)
        {
            String name = Thread.currentThread().getName();
            if(money<m)
            {
                System.out.println(name+"操作,账户余额不足"+money);
            }
            else {
                System.out.println(name + "操作,账户原有金额" + money);
                System.out.println(name + "操作,取款金额" + m);
                money = money - m;
                System.out.println(name + "操作,取款后的金额" + money);
            }
        }
    }
    
    class  User implements Runnable{
        Account account;
        int money;
        public User(Account account,int money){
            this.account = account;
            this.money=money;
        }
        @Override
        public void run() {
            account.drawing(money);
        }
    }

     发现钱甚至变负数了,说明线程同步的时候这样肯定不行。

    所以需要线程同步与死锁

    而也很简单只需要在方法上加上关键字即可

    即我执行完了方法你再执行。

    synchronized

     就正常了

     然后经过研究我们发现其实synchronized它锁的也可以是对象。

    比如这样

     这样每次可以锁不不同的对象,在多线程的时候因为会共用很多代码块数据等,这样也能完美避免,只针对不同的账户,不针对什么支付宝微信或者淘宝之类。

     

     

     就会先支付宝再微信

  • 相关阅读:
    HDU5343:MZL's Circle Zhou(SAM,记忆化搜索DP)
    动归皆背包——那些做过的背包
    CODEVS 3943 数学奇才琪露诺
    codevs 1540 银河英雄传说
    CODEVS 1004四子连棋
    洛谷1082 同余方程
    洛谷1006 传纸条
    洛谷1508 Likecloud-吃、吃、吃
    洛谷1108 低价购买
    洛谷1156 垃圾陷阱
  • 原文地址:https://www.cnblogs.com/yangj-Blog/p/12967210.html
Copyright © 2011-2022 走看看