• 查漏补缺之——Java多线程


    复习面试题中遇到锁的内容当时大一学习的时候感觉懵懂,现在重新复习一下。

    1.1多线程

      1.1.1线程

        1.什么是线程

        线程是程序执行的一条路径,一个进程中包含多条进程

        2.并行与并发

        并行是两个任务同时运行,甲任务进行的同时,乙任务也在进行

        并发是指两个任务都请求运行,处理器只能处理一个任务,就将两个任务进行轮流进行

           3.Java程序运行原理和JVM的启动是否为多线程

        A:Java程序运行原理

          Java命令会启动Java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程,该进程为主线程,主线程去调用某个main方法

        B:JVM的启动是多线程的吗

          JVM的启动至少启动了垃圾回收线程和主线程,所以是多线程的

           

        证明JVM运行是多线程

    package com.littlepage.test2;
    
    public class Demo {
        @Override
        protected void finalize(){
            System.out.println("rubbish is cleaned");
        }
        public static void main(String[] args) {
            for(int i=0;i<1000000;i++){
                new Demo();
            }
            for(int i=0;i<10000;i++){
                System.out.println("main is doing");
            }
        }
    }

      1.1.1实现方式

        1.继承Thread类

    public class TreadDemo01 {
        public static void main(String[] args) {
            MyThread mt=new MyThread();
            mt.start();
            for(int i=0;i<1000;i++){
                System.out.println("Main method");
            }
        }
    }
    
    class MyThread extends Thread{
        @Override
        public void run() {
            for(int i=0;i<1000;i++){
                System.out.println("My Thread is running");
            }
        }
    }

        2.实现runnable接口

    package com.littlepage.test2;
    
    public class ThreadDemo02 {
        public static void main(String[] args) {
            MyRunnable mr=new MyRunnable();
            new Thread(mr).start();
            for(int i=0;i<1000;i++){
                System.out.println("Main method");
            }
        }
    }
    
    class MyRunnable implements Runnable{
        @Override
        public void run() {
            for(int i=0;i<1000;i++){
                System.out.println("My Runnable is running");
            }
        }
    }

        3.何时使用继承何时使用接口

          一般情况下使用继承的多线程,因为代码简单,接口线程在一个类有了父类的时候,使用接口

        4.匿名内部类进行多线程

    package com.littlepage.test2;
    
    public class ThreadDemo03 {
        public static void main(String[] args) {
            new Thread(){
                @Override
                public void run() {
                    for(int i=0;i<1000;i++){
                        System.out.println("My Thread is running");
                    }
                }
            }.start();
            for(int i=0;i<1000;i++){
                System.out.println("Main method");
            }
        }
    }
    package com.littlepage.test2;
    
    public class ThreadDemo03 {
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i=0;i<1000;i++){
                        System.out.println("My Runnable is running");
                    }
                }
            }).start();
            for(int i=0;i<1000;i++){
                System.out.println("Main method");
            }
        }
    }

    1.2获取线程名和设置线程名

       1.1获取线程名字(线程的默认名字为Thread-0 Thread-1....)

    package com.littlepage.test2;
    
    public class Demo04GetName {
        public static void main(String[] args) {
            new Thread(){
                @Override
                public void run() {
                    System.out.println(getName());
                }
            }.start();
            new Thread(){
                @Override
                public void run() {
                    System.out.println(getName());
                }
            }.start();
        }
    }
    package com.littlepage.test2;
    
    public class Demo04GetName {
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            }).start();;
        }
    }

        1.2设置线程名

    package com.littlepage.test2;
    
    public class Demo04GetName {
        public static void main(String[] args) {
            Thread t1=new Thread(){
                @Override
                public void run() {
                    System.out.println(getName());
                }
            };
            t1.setName("线程0");
            Thread t2=new Thread(){
                @Override
                public void run() {
                    System.out.println(getName());
                }
            };
            t2.setName("线程1");
            
            t1.start();t2.start();
        }
    }

    1.3休眠线程

       1.1简介休眠方法

        Thread.sleep(long millis) 休眠millis毫秒

        Thread.sleep(long millis,int nanosecond) 休眠millis毫秒和nanosecond纳秒

       举例:省略

    1.4守护线程(Daemon)

      守护线程就是我们所说的后台程序,非守护线程结束,守护线程将会立即结束

      举例:

    package com.littlepage.test2;
    
    public class DemoDaemon {
        public static void main(String[] args) {
            Thread a=new Thread(){
                @Override
                public void run() {
                    for(int i=0;i<10000;i++){
                        System.out.println(getName()+"	"+i);
                    }
                }
            };
            Thread b=new Thread(){
                @Override
                public void run() {
                    for(int i=0;i<2;i++){
                        System.out.println(getName()+"	"+i);
                    }
                }
            };
            a.setDaemon(true);
            a.start();
            b.start();
        }
    }

      线程2结束,守护线程1也立即结束

    1.5加入线程

      加入线程join() 当前线程暂停,等待指定的线程执行结束后,再进行执行

      举例:

    package com.littlepage.test2;
    
    public class DemoDaemon {
        public static void main(String[] args) {
            final Thread a=new Thread(){
                @Override
                public void run() {
                    for(int i=0;i<10000;i++){
                        System.out.println(getName()+"	"+i);
                    }
                }
            };
            Thread b=new Thread(){
                @Override
                public void run() {
                    for(int i=0;i<2;i++){
                        if(i==1)
                            try {
                                a.join();//等a线程执行完再执行完,再执行b
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        System.out.println(getName()+"	"+i);
                    }
                }
            };
            a.setDaemon(true);
            a.start();
            b.start();
        }
    }

    1.4同步代码块

      1.4.1什么情况下需要同步

        多线程并发,多段代码同时执行,我们希望某一段代码执行过程中CPU不要切换到其他线程来工作,这时候我们需要同步

        代码示例:

    package com.littlepage.test2;
    
    public class DemoSynchronized {
        public static void main(String[] args) {
            final Printer p=new Printer();
            new Thread(){
                public void run(){
                    while(true) p.print1();
                }
            }.start();
            new Thread(){
                public void run(){
                    while(true) p.print2();
                }
            }.start();
        }
    }
    class Printer{
        public void print1(){
            System.out.print("A");
            System.out.print("P");
            System.out.print("P");
            System.out.print("l");
            System.out.println("e");
        }
        public void print2(){
            System.out.print("B");
            System.out.print("a");
            System.out.print("n");
            System.out.print("a");
            System.out.print("n");
            System.out.println("a");
        }
    }

      这段代码在运行过程中出现了以下情况

      

      原因是,打印过程中进行了切换导致,所以我们需要一个同步锁

    package com.littlepage.test2;
    
    public class DemoSynchronized {
        public static void main(String[] args) {
            final Printer p=new Printer();
            new Thread(){
                public void run(){
                    while(true) p.print1();
                }
            }.start();
            new Thread(){
                public void run(){
                    while(true) p.print2();
                }
            }.start();
        }
    }
    class Printer{
        Object lock=new Object();
        public void print1(){
            synchronized (lock) {
                System.out.print("A");
                System.out.print("P");
                System.out.print("P");
                System.out.print("l");
                System.out.println("e");
            }
        }
        public void print2(){
            synchronized (lock) {
                System.out.print("B");
                System.out.print("a");
                System.out.print("n");
                System.out.print("a");
                System.out.print("n");
                System.out.println("a");
            }
        }
    }

        锁可以是任何一个对象,这边直接new一个Object,但是在两个方法内部,必须用一个lock

    1.5同步方法

    package com.littlepage.test2;
    
    public class DemoSynchronized {
        public static void main(String[] args) {
            final Printer p=new Printer();
            new Thread(){
                public void run(){
                    while(true) p.print1();
                }
            }.start();
            new Thread(){
                public void run(){
                    while(true) p.print2();
                }
            }.start();
        }
    }
    class Printer{
        public synchronized void print1(){
            System.out.print("A");
            System.out.print("P");
            System.out.print("P");
            System.out.print("l");
            System.out.println("e");
        }
        public synchronized void print2(){
            System.out.print("B");
            System.out.print("a");
            System.out.print("n");
            System.out.print("a");
            System.out.print("n");
            System.out.println("a");
        }
    }

        同步方法的锁是this, 所以我们有个想法, 包括同步代码块和同步代码,我们所有的锁都可以用this关键字, 不用Object造成冗余

        静态方法的锁是字节码对象

    1.6线程的安全问题

      1.6.1书本的售票例子

    package com.littlepage.test2;
    
    public class DemoTicket {
        public static void main(String[] args) {
            new TicketSeller("窗口1").start();
            new TicketSeller("窗口2").start();
            new TicketSeller("窗口3").start();
            new TicketSeller("窗口4").start();
        }
    }
    class TicketSeller extends Thread{
        private static int tickets=100;
        
        public TicketSeller(String windowName) {
            super(windowName);
        }
        
        public  void run(){
            while(true){
                if(tickets<=0){
                    break;
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getName()+"......"+tickets--);
            }
        }
    }

       结果出现了重复票和负票

        

      解决方式,加上同步代码块

    package com.littlepage.test2;
    
    public class DemoTicket {
        public static void main(String[] args) {
            new TicketSeller("窗口1").start();
            new TicketSeller("窗口2").start();
            new TicketSeller("窗口3").start();
            new TicketSeller("窗口4").start();
        }
    }
    class TicketSeller extends Thread{
        private static int tickets=100;
        
        public TicketSeller(String windowName) {
            super(windowName);
        }
        
        public  void run(){
            synchronized (TicketSeller.class) {
                while(true){
                    if(tickets<=0){
                        break;
                    }
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(getName()+"......"+tickets--);
                }
            }
        }
    }

      使用Runnable实现

    1.7死锁

      

  • 相关阅读:
    事务1-JDBC事务管理
    Tomcat地址栏传中文参数乱码问题处理
    hibernate报错:org.hibernate.MappingException: No Dialect mapping for JDBC type: -1
    UVA12170 Easy Climb
    [POI2004]旅行问题
    [SCOI2010]股票交易
    [USACO11OPEN] Mowing the Lawn G
    查看文件个数 ls |wc -l
    【zombie】如何查看并杀死僵尸进程?
    [Windows] 屏幕截图
  • 原文地址:https://www.cnblogs.com/littlepage/p/10665401.html
Copyright © 2020-2023  润新知