• JAVASE02-Unit010: 多线程基础 、 TCP通信


        多线程基础 、 TCP通信    

     * 当一个方法被synchronized修饰后,那么
     * 该方法称为同步方法,即:多个线程不能同时
     * 进入到方法内部执行。

    package day10;
    /**
     * 当多线程并发操作同一资源时,由于线程切换的不确定
     * 性,可能导致执行顺序的混乱,严重时可能导致系统
     * 瘫痪。
     * @author adminitartor
     *
     */
    public class SyncDemo1 {
        public static void main(String[] args) {
            final Table table = new Table();
            Thread t1 = new Thread(){
                public void run(){
                    while(true){
                        int bean = table.getBean();
                        Thread.yield();//模拟线程切换
                        System.out.println(getName()+":"+bean);
                    }
                }
            };
            Thread t2 = new Thread(){
                public void run(){
                    while(true){
                        int bean = table.getBean();
                        Thread.yield();//模拟线程切换
                        System.out.println(getName()+":"+bean);
                    }
                }
            };
            
            t1.start();
            t2.start();
        }
    }
    
    class Table{
        private int beans = 20;
        /**
         * 当一个方法被synchronized修饰后,那么
         * 该方法称为同步方法,即:多个线程不能同时
         * 进入到方法内部执行。
         * 在方法上使用synchronized那么锁对象为
         * 当前方法所属对象,即:this
         * @return
         */
        public synchronized int getBean(){
            if(beans==0){
                throw new RuntimeException("没有豆子了!");
            }
            Thread.yield();//模拟线程切换
            return beans--;
        }
    }
    SyncDemo1.java

     * 有效的缩小同步范围可以在保证并发安全的前提下
     * 提高并发效率。

    package day10;
    /**
     * 有效的缩小同步范围可以在保证并发安全的前提下
     * 提高并发效率。
     * @author adminitartor
     *
     */
    public class SyncDemo2 {
        public static void main(String[] args) {
            final Shop shop = new Shop();
            Thread t1 = new Thread(){
                public void run(){
                    shop.buy();
                }
            };
            Thread t2 = new Thread(){
                public void run(){
                    shop.buy();
                }
            };
            t1.start();
            t2.start();
        }
    }
    
    class Shop{
        public void buy(){
            try {
                Thread t = Thread.currentThread();
                System.out.println(t.getName()+":正在挑选衣服...");
                Thread.sleep(5000);
                /*
                 * 多个线程要保证同步执行代码的前提是
                 * 这里看到的"同步监视器"即:上锁的对象
                 * 是同一个。
                 */
                synchronized(this){
                    System.out.println(t.getName()+":正在试衣服...");
                    Thread.sleep(5000);
                }
                System.out.println(t.getName()+":结账离开");
            } catch (Exception e) {
                e.printStackTrace();
            }
            
        }
    }
    SyncDemo2.java

     * 每个类在被JVM加载时,JVM都会创建一个且只创建
     * 一个Class类型的实例来表示它。所以,每个类在
     * JVM内部都有唯一的一个Class类型的实例对应,而
     * 静态方法就是将该Class的实例上锁的。

    package day10;
    /**
     * 静态方法若使用synchronized修饰后,那么该方法
     * 一定具有同步效果。
     * 静态方法的同步监视器对象为当前类的类对象。
     * 类对象:Class类型的实例。
     * 每个类在被JVM加载时,JVM都会创建一个且只创建
     * 一个Class类型的实例来表示它。所以,每个类在
     * JVM内部都有唯一的一个Class类型的实例对应,而
     * 静态方法就是将该Class的实例上锁的。
     * @author adminitartor
     *
     */
    public class SyncDemo3 {
        public static void main(String[] args) {
            Thread t1 = new Thread(){
                public void run(){
                    Foo.dosome();
                }
            };
            Thread t2 = new Thread(){
                public void run(){
                    Foo.dosome();
                }
            };
            t1.start();
            t2.start();
        }
    }
    
    class Foo{
        public synchronized static void dosome(){
            try {
                Thread t = Thread.currentThread();
                System.out.println(t.getName()+":正在运行dosome方法...");
                Thread.sleep(5000);            
                System.out.println(t.getName()+":运行dosome方法完毕!");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    SyncDemo3.java

     * 互斥锁

    package day10;
    /**
     * 互斥锁
     * 当使用Synchronized修饰多段不同代码,但是同步
     * 监视器对象是同一个的时候,那么这些代码间就具有
     * 了互斥性,同一时间不能同时执行这些代码。
     * @author adminitartor
     *
     */
    public class SyncDemo4 {
        public static void main(String[] args) {
            final Boo boo = new Boo();
            Thread t1 = new Thread(){
                public void run(){
                    boo.methodA();
                }
            };
            Thread t2 = new Thread(){
                public void run(){
                    boo.methodB();
                }
            };
            t1.start();
            t2.start();
         }
    }
    
    class Boo{
        public void methodA(){
            synchronized(this){
                try {
                    Thread t = Thread.currentThread();
                    System.out.println(
                     t.getName()+":正在执行A方法");
                    Thread.sleep(5000);
                    System.out.println(
                     t.getName()+":执行A方法完毕");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        public void methodB(){
            synchronized(this){
                try {
                    Thread t = Thread.currentThread();
                    System.out.println(t.getName()+":正在执行B方法");
                    Thread.sleep(5000);
                    System.out.println(t.getName()+":执行B方法完毕");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    SyncDemo4.java

     * 死锁

    package day10;
    /**
     * 死锁
     * 双方都持有自己的锁,但都要求对方先释放锁时
     * 出现死锁现象。
     * @author adminitartor
     *
     */
    public class SyncDemo5 {
        public static void main(String[] args) {
            final Coo coo = new Coo();
            Thread t1 = new Thread(){
                public void run(){
                    coo.methodA();
                }
            };
            Thread t2 = new Thread(){
                public void run(){
                    coo.methodB();
                }
            };
            t1.start();
            t2.start();
        }
    }
    
    class Coo{
        private Object lockA = new Object();
        private Object lockB = new Object();
        
        public void methodA(){
            try {
                Thread t = Thread.currentThread();
                synchronized (lockA) {
                    System.out.println(t.getName()+"正在运行A方法");
                    Thread.sleep(5000);
                    methodB();
                    System.out.println(t.getName()+"运行A方法完毕");
                }
                
            } catch (Exception e) {
            }
        }
        public void methodB(){
            try {
                Thread t = Thread.currentThread();
                synchronized (lockB) {
                    System.out.println(t.getName()+"正在运行B方法");
                    Thread.sleep(5000);
                    methodA();
                    System.out.println(t.getName()+"运行B方法完毕");
                }
                
            } catch (Exception e) {
            }
        }
    }
    SyncDemo5.java

     * 使用Collections的静态方法可以将现有的集合
     * 或Map转换为线程安全的

    package day10;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    /**
     * 使用Collections的静态方法可以将现有的集合
     * 或Map转换为线程安全的
     * @author adminitartor
     *
     */
    public class Sync_API {
        public static void main(String[] args) {
            /*
             * 线程安全的集合自身的add,remove等方法
             * 都是同步的,并且之间也有互斥。
             * 但是并不与迭代器遍历互斥。所以若并发
             * 同时遍历和增删元素,迭代器依然会抛出
             * 异常。
             * 所以,迭代器与集合元素操作间要自行维护
             * 互斥关系。
             * 
             * ArrarList,LinkedList都不是线程安全的
             */
            List<String> list 
                = new ArrayList<String>();        
            list.add("one");
            list.add("two");
            list.add("three");    
            list.add("four");
            System.out.println(list);
            //将给定的集合转换为一个线程安全的集合
            list = Collections.synchronizedList(list);
            
            System.out.println(list);
            
            
            Set<String> set 
                = new HashSet<String>(list);
            set = Collections.synchronizedSet(set);
            System.out.println(set);
            
            
            Map<String,Integer> map
                = new HashMap<String,Integer>();
            map.put("语文", 100);
            map.put("数学", 99);
            map.put("英语", 98);
            
            map = Collections.synchronizedMap(map);
            System.out.println(map);
        }
    }
    Sync_API.java

     * 线程池

    package day10;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    /**
     * 线程池
     * 线程池有两个主要作用:
     * 1:控制线程数量
     * 2:重用线程
     * @author adminitartor
     *
     */
    public class ThreadPool_Demo {
        public static void main(String[] args) {
            ExecutorService threadPool
                = Executors.newFixedThreadPool(2);
            
            for(int i=0;i<5;i++){
                Runnable runn = new Runnable(){
                    public void run(){
                        Thread t = Thread.currentThread();
                        System.out.println(t.getName()+":正在运行任务...");
                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(t.getName()+":运行任务完毕!");
                    }
                };
                threadPool.execute(runn);
            }
        
            //结束线程池
            threadPool.shutdown();
            System.out.println("线程池结束了!");
        }
    }
    ThreadPool_Demo.java

    案例一:

     * 封装了TCP通讯的Socket
     * 使用它可以与服务端建立连接,并进行通讯

    package chat;
    
    import java.net.Socket;
    
    /**
     * 聊天室客户端
     * @author adminitartor
     *
     */
    public class Client {
        /*
         * 封装了TCP通讯的Socket
         * 使用它可以与服务端建立连接,并进行通讯
         * 
         */
        private Socket socket;
        /**
         * 构造方法,用来初始化客户端
         */
        public Client() throws Exception{
            /*
             * 实例化Socket的过程就是连接服务端的
             * 过程。若连接失败,这里会抛出异常
             * 
             * 构造方法的两个参数:
             * 1:服务端计算机的IP地址
             * 2:服务端应用程序的端口
             */
            socket = new Socket(
                "localhost",8088    
            );
        }
        /**
         * 客户端开始工作的方法
         */
        public void start(){
            
        }
        
        public static void main(String[] args) {
            try {
                Client client = new Client();
                client.start();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("客户端运行失败!");
            }
        }
    }
    Client.java

     * 聊天室服务端

    package chat;
    
    import java.net.ServerSocket;
    import java.net.Socket;
    
    /**
     * 聊天室服务端
     * @author adminitartor
     *
     */
    public class Server {
        /*
         * 运行在服务端的ServerSocket,主要作用:
         * 1:向操作系统申请服务端口,客户端就是通过
         *   这个端口与服务端程序建立连接的
         * 2:监听服务端口,一旦客户端连接了,就会创建
         *   一个Socket以便与该客户端交互  
         */
        private ServerSocket server;
        
        /**
         * 构造方法,用来初始化服务端
         * @throws Exception
         */
        public Server() throws Exception{
            /*
             * 初始化,并申请服务端口,若该端口被
             * 其他应用程序占用,这里会抛出异常
             */
            server = new ServerSocket(8088);
        }
        
        public void start(){
            try {
                /*
                 * ServerSocket提供方法:
                 * Socket accept() 
                 * 该方法是一个阻塞方法,直到一个客户端
                 * 通过申请的端口连接上,这里才会返回
                 * 返回的是一个Socket实例,通过该实例
                 * 即可与刚连接的客户端交互。
                 */
                System.out.println("等待客户端连接...");
                Socket socket = server.accept();
                System.out.println("一个客户端连接了!");
                
                
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        public static void main(String[] args) {
            try {
                Server server = new Server();
                server.start();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("服务端运行失败!");
            }
        }
    }
    Server.java
  • 相关阅读:
    Lambda表达式 Lambda expression(1)
    解密随机数生成器(2)——从java源码看线性同余算法(转)
    解密随机数生成器(1)——真随机数生成器(转)
    HTML标签 table(4)
    HTML标签详解(3)
    Flink DataStream API
    Apache Flink Watermark
    Flink核心概念
    Flink SQL and Table
    Hive ORC File Format
  • 原文地址:https://www.cnblogs.com/tangshengwei/p/6260479.html
Copyright © 2020-2023  润新知