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

Posted 唐胜伟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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

 

以上是关于JAVASE02-Unit010: 多线程基础 TCP通信的主要内容,如果未能解决你的问题,请参考以下文章

JAVASE02-Unit012: Unit07: XML语法 XML解析

JAVASE02-Unit05: 集合操作 —— 查找表

JAVASE02-Unit04: 集合框架 集合操作 —— 线性表

JavaSE8基础 多线程setDaemon 守护线程

JavaSE8基础 多线程join 线程加入

JavaSE8基础 多线程interrupt 线程中断