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--; } }
* 有效的缩小同步范围可以在保证并发安全的前提下
* 提高并发效率。
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(); } } }
* 每个类在被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(); } } }
* 互斥锁
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(); } } } }
* 死锁
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) { } } }
* 使用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); } }
* 线程池
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("线程池结束了!"); } }
案例一:
* 封装了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("客户端运行失败!"); } } }
* 聊天室服务端
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("服务端运行失败!"); } } }
以上是关于JAVASE02-Unit010: 多线程基础 TCP通信的主要内容,如果未能解决你的问题,请参考以下文章
JAVASE02-Unit012: Unit07: XML语法 XML解析