zoukankan      html  css  js  c++  java
  • day11 线程


    进程:是一个正在这行中的进程。
        每一个进程执行都有一个执行顺序。该顺序是一个执行路径,或者叫一个控制单元。
    线程:就是进程中的一个独立的控制单元。
        线程在控制者进程的执行。
        
    一个进程中至少有一个线程。

    java vm 启动的时候会有一个进程java.exe。
    该进程中至少有一个线程负责java程序的执行。
    而且这个线程运行代码存在于main方法中
    该线程称之为主线程。

    扩展:其实更细节说明jvm,jvm启动不至一个线程,还有负责垃圾回收机制的线程。

    1,如何在自定义的代码中,定义一个线程。

    通过API的查找,java已经提供了对线程这类事物的描述。就是Thread类。

    创建线程的第一种方法:继承Therad类。

    步骤:
    1,定义类继承thread
    2,复写thread类中的run方法
    3,调用线程的start方法、该方法有两个作用:启动线程,调用run方法、

    发现运行结果每一次都不同、
    因为多个线程都获取cpu执行权,cpu执行到谁,谁就运行。
    明确一点在某一个时刻,只能有一个程序在运行。(多核除外)
    cpu在做着快速的切换,以达到看上去是同时运行的效果。
    我们可以形象吧多线程的运行行为在互相抢夺cpu的执行权。

    这就是多线程的一个特性:随机性。 谁抢到谁执行,至于执行多长,cpu说了算。

    自定义一个线程

    class  Demo extends   Thread
    {
        public void run()
        {
            for(int i=0;i<60;i++)
            System.out.println("demo run---"+i);
        }
    }
    
    class ThreadDemo
    {
        public static void main(String[] args)
        {
            Demo d = new Demo();//创建好一个线程;
            d.start();//启动线程,调用run方法、
            for(int i=0;i<60;i++)
            System.out.println("run -- "+i);
        }
    }

     
    需求:简单的买票程序。

    多个窗口同时买票。

    创建线程的第二种方式:实现Runable接口

    步骤:
    1,定义类实现Runnable接口
    2,覆盖Runnable接口中的run方法
        将线程要运行的代码存放在run方法中
        
    3,通过Thread类建立线程对象
    4,将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数。
        为什么要将Runnable接口的子类对象传递给Thread的构造函数。
        因为,自定义的run方法所属的对象是Runnable接口的子类对象。
        所以要让线程去指定指定对象的run方法。就必须明确该run方法所属对象。
        
    5,调用Thread类的start方法开启线程并调用Runnable接口子类的run方法


    实现方式和继承方式有什么区别呢?

    实现方式好处:避免了实现单继承的局限性/
    在定义线程是,建议使用实现方式

    两中方式区别:
    继承Thread:线程代码存放Thread子类run方法中
    实现Runable,线程代码存在接口的子类的run方法。

    出现安全隐患

    class
    Ticket implements Runnable//extends Thread { private int tick = 100; public void run() { while(true) { if(tick>0) { System.out.println(Thread.currentThread().getName()+"sale : "+ tick--); } } } } class TicketDemo { public static void main(String[] args) { Ticket t = new Ticket(); //Ticket t = new Ticket(); Thread t1 = new Thread(t); Thread t2 = new Thread(t); Thread t3 = new Thread(t); Thread t4 = new Thread(t); t1.start(); t2.start(); t3.start(); t4.start(); } }

     
    通过分析,发现,打印出0,-1,-2等错票。

    多线程的运行出现安全问题。

    问题的原因:
        当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
        另一个线程参与进来执行。导致共享数据的错误。
        
    解决办法:
        对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
        
    java对于多线程的安全问题提供了专业的解决方式。

    就是同步代码块

    synchronized(对象)
    {
        需要被同步的代码。
    }

    class Ticket implements Runnable//extends Thread
    {
        private int tick = 100;
        Object obj = new Object();
        public void run()
        {
            while(true)
            {
                    synchronized(obj)
                    {
                        if(tick>0)
                        {
                            try{Thread.sleep(10);}catch(Exception e){}
                            System.out.println(Thread.currentThread().getName()+"sale : "+ tick--);
                        }
                    }
            }
        }
    }
    
    class TicketDemo
    {
        public static void main(String[] args)
        {
            
            Ticket t = new Ticket();
            //Ticket t = new Ticket();
            
            Thread t1 = new Thread(t);
            Thread t2 = new Thread(t);
            Thread t3 = new Thread(t);
            Thread t4 = new Thread(t);
            
            t1.start();
            t2.start();
            t3.start();
            t4.start();
            
        }
    }

     
    对象如同锁。持有锁的线程可以在同步中执行。
    没有持有锁的线程即使获取cpou的执行权,也进不去,因为没有获取锁。



    同步的前提:
    1,必须要有两个或者多个以上的线程。
    2,必须是多个线程使用同一个锁。


    必须保证同步中只能有一个线程在运行。

    好处:解决了多线程的安全问题

    弊端:多个线程需要判断锁,较为消耗资源


    //需求:
    银行有一个金库。
    有两个储户分别存300元,每次存100,存3次:

    目的;改程序是否有安全问题,如果有,如何解决?

    如何找问题:
    1,明确哪些代码是多线程运行代码
    2,明确共享数据
    3,明确多线程运行代码中哪些语句是操作共享数据的。

    同步函数用的哪一个锁呢?
    函数需要被函数调用。那么函数都有一个所属函数的引用。就是this、
    所以同步函数使用的锁是this。

    class Bank
    {
        private int sum;
        public synchronized void add(int n)
        {
            sum += n;
            
            System.out.println("sum="+sum);
        }
    }
    
    
    class Cus implements Runnable//extends Thread
    {
        private Bank b = new Bank();
        
        public void run()
        {
            for(int x=0;x<3;x++)
                b.add(100);
        }
    }
    
    class TicketDemo
    {
        public static void main(String[] args)
        {
            
            Cus t = new (Cus);
            //Ticket t = new Ticket();
            
            Thread t1 = new Thread(t);
            Thread t2 = new Thread(t);
            //Thread t3 = new Thread(t);
            //Thread t4 = new Thread(t);
            
            t1.start();
            t2.start();
            
            
        }
    }

     
    如果同步函数被静态修饰后,使用的锁是什么呢?

    通过验证,发现不在是this,因为静态方法中也不可以定义this。

    静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象。
    类名.class 该对象的类型是class、

    静态的同步方法,使用的锁是该方法所在类的字节码文件对象。类名.class


    锁的应用(多线程)

    单例设计模式。
    
    
    饿汉式
    
    class Single
    {
        private static final Single s = new Single();
        private Single(){};
        public static Single getInstance()
        {
            return s;
        }
        
    }
    
    懒汉式
    
    
    class Single 
    {
        private static Single s = null;
        private Single(){}
        public static Single getInstance()
        {
            
            if(s==null)            
            {
                synchronized(Single.class)    //提高效率(在函数体上加synchronized)
                {
                    if(s==null)
                        s = new Single();
                }
            }
            return s;
        }
    }


    死锁 程序

    class Test implements Runnable
    {
        private boolean flag;
        Test(boolean flag)
        {
            this.flag = flag;
        }
        public void run()
        {
            if(flag)
            {
                synchronized(MyLock.locka)
                {
                    System.out.println("if locka");
                    synchronized(MyLock.lockb)
                    {
                        System.out.println("if lockb");
                    }
                }
            }
            else
            {
                synchronized(MyLock.lockb)
                {
                    System.out.println("else lockb");
                    synchronized(MyLock.locka)
                    {
                        System.out.println("elce locka");
                    }
                }
            }
        }
    }
    
    
    class MyLock
    {
        static Object locka = new Object();
        static Object lockb = new Object();
    }
    class DeadLockTest 
    {
        public static void main(String[] args)
        {
            Thread t1 = new Thread(new Test(true));
            Thread t2 = new Thread(new Test(false));
            t1.start();
            t2.start();
        }
    }
  • 相关阅读:
    POJ 2240 Arbitrage spfa 判正环
    POJ 3259 Wormholes spfa 判负环
    POJ1680 Currency Exchange SPFA判正环
    HDU5649 DZY Loves Sorting 线段树
    HDU 5648 DZY Loves Math 暴力打表
    HDU5647 DZY Loves Connecting 树形DP
    CDOJ 1071 秋实大哥下棋 线段树
    HDU5046 Airport dancing links 重复覆盖+二分
    HDU 3335 Divisibility dancing links 重复覆盖
    FZU1686 神龙的难题 dancing links 重复覆盖
  • 原文地址:https://www.cnblogs.com/WDKER/p/5630674.html
Copyright © 2011-2022 走看看