多线程
一、目前存在的问题
程序同一时间只能做一件事
二(??)
创建多线程的方法
-
继承Thread类
-
实现Runnable接口
-
实现Callable接口
-
线程池创建
三、继承Thread类创建线程
-
自定义线程类继承Thread类
-
重写run方法 -- run方法中的内容就是线程体
-
创建自定义线程类的对象
-
调用start方法启动线程
public class ChatThread extends Thread{ @Override public void run() { for(int i = 0;i < 100; i++){ System.out.println("聊天"); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public class EatThread extends Thread { @Override public void run() { for(int i = 0;i < 100; i++){ System.out.println("吃饭"); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public class DrinkThread extends Thread{ @Override public void run() { for(int i = 0;i < 100; i++){ System.out.println("喝酒"); try { Thread.sleep(100); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } public static void main(String[] args) { //创建线程类的对象 DrinkThread drinkThread = new DrinkThread(); ChatThread chatThread = new ChatThread(); EatThread eatThread = new EatThread(); //启动线程 drinkThread.start(); chatThread.start(); eatThread.start(); }
ps.
-
启动线程用start(),不能用run()
start()只能调用一次
-
run()
和start()
的区别?
-
start()
:用来启动线程,通过该线程调用run
方法执行run
方法中所定义的逻辑代码。start
方法只能被调用一次。 -
run()
:封装了要被线程执行的代码,可以被调用多次。
四、runnable
步骤:
-
自定义线程类,实现runnable接口
-
在自定义类中,实现run方法
-
创建自定义类对象并将该对象传入Thread类的构造方法中得到Thread类的对象
-
调用Thread类的start方法启动线程
优势:
-
避免了单继承的局限性;
-
多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。
MyThread t1 = new MyThread(); MyThread t2 = new MyThread(); t1.setName("线程1"); t2.setName("线程2"); t1.start(); t2.start(); for(int i = 1; i <= 100; i++){ System.out.println(Thread.currentThread().getName() + ":" + i); }//currentThread --获取当前线程的引用 //getName() -- 获取当前线程的名字 //setName() -- 为线程设置名字
Thread th1 = new Thread(new Runnable() { @Override public void run() { System.out.println("t1"); } }); Thread th2 = new Thread(new Runnable() { @Override public void run() { try { th1.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("t2"); } }); Thread th3 = new Thread(new Runnable() { @Override public void run() { try { th2.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("t3"); } }); th3.start(); th2.start(); th1.start();
public class MyThread extends Thread { private Thread t; public MyThread(Thread t){ this.t = t; } public void run(){ try { if (t != null) { t.join(); } } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println(Thread.currentThread().getName()); } } public class MyTest1 { public static void main(String[] args) { Thread t1 = new MyThread(null); Thread t2 = new MyThread(t1); MyThread t3 = new MyThread(t2); t1.setName("线程1"); t2.setName("线程2"); t3.setName("线程3"); t3.start(); t1.start(); t2.start(); } }
public class MyTest1 { public static void main(String[] args) { Window w = new Window(); Thread w1 = new Thread(w); Thread w2 = new Thread(w); Thread w3 = new Thread(w); w1.setName("窗口1"); w2.setName("窗口2"); w3.setName("窗口3"); w1.start(); w2.start(); w3.start(); } } public class Window implements Runnable{ private Integer no = 100; @Override public void run() { while(true){ synchronized (no){ if(no <= 0){ break; } System.out.println(Thread.currentThread().getName() + "销售第" + no + "张票"); no--; } try { Thread.sleep(10); } catch (InterruptedException e) { throw new RuntimeException(e); } } } }
public class MyTest2 { private static SingleObject obj1; private static SingleObject obj2; public static void main(String[] args) throws InterruptedException{ Thread t1 = new Thread(new Runnable() { @Override public void run() { obj1 = SingleObject.getObject(); } }); Thread t2 = new Thread(new Runnable() { @Override public void run() { obj2 = SingleObject.getObject(); } }); t1.start(); t2.start(); Thread.sleep(1000); System.out.println(obj1 == obj2); } } //一会true一会false的?????????????????????????????
五、Thread类方法
-
start()
:启动线程,并执行对象的run()
方法; -
run()
:线程在被调用时执行的操作; -
getName()
:返回线程的名称; -
setName()
:设置线程的名称; -
currentThread()
:返回当前线程。
六、线程的调度和生命周期
-
调度策略:
-
基于时间片轮转
-
抢占式
-
生命周期:
-
新建(NEW)
-
可运行(RUNNABLE)
-
终结(TERMINATED)
-
阻塞(BLOCKED)
-
等待(WAITING)
-
有时限等待(TIMED_WAITING)
七、死锁
-
死锁:不同的线程分别占用对方需要的同步资源
网络编程
网络编程
1. 目的
直接或间接地通过网络协议与其他计算机进行通讯
2.需要解决的问题
-
如何准确地定位网络上一台或多台主机:
IP
-
如何定位主机上的特定应用:
端口
-
找到主机后如何可靠高效地进行数据传输"
协议
3.网络通信
-
设备和设备
-
进程和进程
1)不同设备之间
2)本地设备之间
网络协议
1.OSI
应用层,表示层,会话层,传输层,网络层,数据链路层,物理层
2.TCP\IP
-
以TCP和IP为主的一系列应用层协议
应用层, 传输层,网络层, 数据链路层
3.TCP和UDP
IP地址和端口号
1.ip地址
唯一的标识Internet上的计算机(通信实体)。
2.本地回环地址
127.0.0.1
3.ip地址分类方式
1)
-
IPV4:4个字节组成,4个0-255。以点分十进制表示,如
192.168.0.1
-
IPV6
:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示, 数之间用冒号:
分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:198
2)
-
公网地址(万维网使用)
-
私有地址(局域网使用)
4.端口号
1)标识进程,不同进程有不同的端口号,是一个16位的整数
2)分类
-
公认端口:0~1023
-
注册端口
-
动态/私有端口
3)端口号与IP地址的组合得出一个网络套接字Socket
5.InetAddress类
1)Internet上的主机有两种方式表示地址:
-
域名(stage1.codeaction.org)
-
IP地址
2)InetAddress主要作用是表示IP地址,有两个子类:
-
Inet4Address
-
Inet6Address
3)InetAddress类对象含有一个Internet主机地址的域名和IP地址:
-
stage1.codeaction.org
-
216.127.178.187
4)域名解析过程:
-
先找本机hosts文件,是否有输入的域名地址;
-
没有的话,再通过DNS服务器,找主机。
5)静态方法获取InetAddress
-
public static InetAddress getLocalHost()
-
public static InetAddress getByName(String host)
6)常用方法
-
public String getHostAddress()
:返回IP地址字符串
(以文本表现形式) -
public String getHostName()
:获取此IP地址的主机名
-
public boolean isReachable(int timeout)
:测试是否可以达到该地址
6.Socket
通信的两端(客户端、服务端)都要有Socket
,是两台机器间通信的端点。
网络通信其实就是Socket
间的通信。
1)Socket分类
-
流套接字:使用
TCP
提供可依赖的字节流服务 -
数据报套接字:使用
UDP
提供尽力而为的数据报服务。
2)常用构造器
-
public Socket(InetAddress address, int port)
创建一个流套接字并将其连接到指定IP
地址的指定端口号; -
public Socket(String host, int port)
创建一个流套接字并将其连接到指定主机上的指定端口号。
3)常用方法
-
getLocalAddress()
:返回本地Socket
中的IP
的InetAddress
对象; -
getLocalPort()
:返回本地Socket
中的端口号; -
getInetAddress()
:返回对方Socket
中IP
地址; -
getPort()
:返回对方Socket
中的端口号; -
close()
:关闭套接字; -
getInputStream()
:获取输入流,用来读取数据; -
getOutputStream()
:获取输出流,用来发送数据。
基于TCP/IP的服务器和客户端
作用:1.客户端能够连接服务器
-
客户端能够给服务器
//服务器 public class Server{ main{ //创建监听套接字 ServerSocket st = new ServerSocket(60000); while(true){ //创建连接套接字 - 表示有客户端连接 Socket socket = st.accept(); int len = 0; //IO操作 InputStream in = socket.getInputStream(); while(true){ len = in.read(arr,0,arr.length); if(len == -1){ break; } String s = new String(arr,0,len); sout(s); } //关闭套接字 socket.close(); } } }