1、 聊天程序案例
单线程版本:
public class Server {
public static void main(String[] args) {
// 服务端
// List<Socket> lists = new ArrayList<>();
try {
// System.out.println(InetAddress.getLocalHost().getAddress());
// 192.168.78.1
ServerSocket server = new ServerSocket(1223);
Socket c = server.accept();
System.out.println("有人上线");
PrintWriter out = new PrintWriter(c.getOutputStream()); // 发信息
BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); // 收信息
while (true){
// 先收信息
String msg = br.readLine();
System.out.println(msg);
// 发信息
System.out.println("发信息:");
String info = new Scanner(System.in).nextLine() + "\r\n";
out.write(info);
out.flush();
}
/* while (true){
Socket c = server.accept(); // 中断
list.add(c);
System.out.println("有人连线");
} */
} catch (Exception e){
e.printStackTrace();
}
}
}
public class Client {
public static void main(String[] args) {
// 客户端
try {
Socket c= new Socket("192.168.78.1",1223);
PrintWriter out = new PrintWriter(c.getOutputStream()); // 发信息
BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream())); // 收信息
while (true) {
System.out.println("发信息");
String msg = new Scanner(System.in).nextLine() + "\r\n";
out.write(msg);
out.flush();
String info = br.readLine();
System.out.println(info);
}
} catch (Exception e){
e.printStackTrace();
}
}
}
实现效果:
多线程版本:Server、Client、Read接收类、Send发送类
public class ChatUtil {
private PrintWriter writer;
private BufferedReader reader;
private String title;
public ChatUtil(PrintWriter writer, BufferedReader reader, String title) {
this.writer = writer;
this.reader = reader;
this.title = title;
}
/*
发信息
*/
public void a(){
while (true){
// 发信息
String info = title + ":" + new Scanner(System.in).nextLine() + "\r\n";
writer.write(info);
writer.flush();
}
}
public void b(){
while (true){
try {
// 先收信息
String msg = reader.readLine();
System.out.println(msg);
} catch (Exception e){
e.printStackTrace();
}
}
}
public PrintWriter getWriter() {
return writer;
}
public void setWriter(PrintWriter writer) {
this.writer = writer;
}
public BufferedReader getReader() {
return reader;
}
public void setReader(BufferedReader reader) {
this.reader = reader;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
public class Server {
public static void main(String[] args) {
try {
ServerSocket server = new ServerSocket(5595);
Socket c = server.accept();
PrintWriter writer = new PrintWriter(c.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(c.getInputStream()));
ChatUtil cu = new ChatUtil(writer,reader,"服务器");
new Thread(cu::a).start();
new Thread(cu::b).start();
} catch (Exception e){
e.printStackTrace();
}
}
}
public class Client {
public static void main(String[] args) {
try {
Socket c = new Socket("localhost",5595);
PrintWriter writer = new PrintWriter(c.getOutputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(c.getInputStream()));
ChatUtil cu = new ChatUtil(writer,reader,"客户端");
new Thread(cu::a).start();
new Thread(cu::b).start();
} catch (Exception e){
e.printStackTrace();
}
}
}
实现效果:
2、 线程状态
- 新建(NEW):新创建了一个线程对象。
- 可运行(RUNNABLE):线程对象创建后,其他线程(比如main线程)调用了该对象的start() 方法。该状态的线程位于可运行线程池中,等待被线程调用选中,获取cpu的使用权。
- 运行(RUNNING):可运行状态(runnable)的线程获得了cpu的时间片(timeslice),执行程序代码。
- 阻塞(BLOCKED):阻塞状态是指线程因为某种原因放弃了cpu使用权,也即让出了cputimeslice,暂时停止运行,直到线程进入可运行(runnable)状态,才有机会再次获得cputimeslice转到运行(running)状态,阻塞的情况分三种:
① 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
② 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
③ 其他阻塞:运行(running)的线程执行Thread.sleep(long ms) 或 t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep() 状态超时、join() 等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。 - 死亡(DEAD):线程run()、main()方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
3、 线程优先级别
当程序分为多个线程运行时,每个线程都会得到一小段CPU时间来运行,运行时间结束后,将轮换另一个线程进入运行状态,JVM会优先选择优先级高的线程进入运行状态。但这并不意味着优先级底的线程得不到运行,JVM会自动对一段时间内没有得到时间片运行的线程提高优先级。
线程的优先级是由1-10之间的数字来表示的,数字1表示最低优先级,数字10表示最高优先级,默认优先级是5。
Thread类的setPriority() 方法可以设置线程的优先级,方法说明如下:
void setPriority (int newPriority)
该方法用于更改当前线程的优先级,优先级高的线程会优先运行,同样优先级的线程排在前面的会优先运行。newPriority为设置的优先级数字,如果该数字不在1-10范围之类,会抛出IllegalArgumentException异常(参数异常)。
void setPriority (int newPriority)
t.setPriority(Thread.MAX_PRIORITY);
t.setPriority(Thread.NORM_PRIORITY);
t.setPriority(Thread.MIN_PRIORITY);
int tp = t.getProority();
4、 线程名称设置
// 实现Runnable接口,重写run方法,将此类的实例作为Thread类的参数,来开启线程执行
Th2 th2 = new Th2();
// th2线程对象,"AA"是当前这个线程的名称
Thread t1 = new Thread(th2,"AA");
t1.setName("A线程");
Thread t2 = new Thread(th2,"BB");
FutureTask<Integer> f1 = new FutureTask<>(new Th6(10000));
Thread t = new Thread(f1,"F1线程");
FutureTask<Integer> f2 = new FutureTask<>(new Th6(100));
Thread t2 = new Thread(f2,"f2线程");
5、 Timer TimerTask工具类
Timer类的常用其他方法:
cancel()
终止此计时器,丢弃所有当前已安排的任务。
purge()
从此计时器的任务队列中移除所有已取消的任务
schedule(TimerTask task, Date time)
安排在指定的时间执行指定的任务。
TimerTask类的常用其他方法:
cancel()
取消此计时器任务。
run()
此计时器任务要执行的操作。
scheduledExecutionTime()
返回此任务最近行的已安排执行时间。
public class TimerTest {
public static void main(String[] args) throws ParseException {
/*
schedule和scheduleAtFixedRate的区别在于,如果指定开始执行的时间
在当前系统运行时间之前,scheduleAtFixedRate会把过去的时间也作为周
期执行,而schedule不会把过去的时间算上。
*/
Timer t = new Timer();
t.schedule(new TimerTask() {
@Override
public void run() {
System.out.printf("%1$tF%1$tT%n", System.currentTimeMillis());
// t.cancel();
}
}, 5000, 1000);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyyy-MM-dd HH:mm:ss");
t.schedule(new TimerTask() {
@Override
public void run() {
t.cancel();
}
}, sdf.parse("2022-10-02 21:00:00"));
Timer t2 = new Timer();
TimerTask tt = new TimerTask() {
@Override
public void run() {
System.out.println("hello world Timer");
t2.cancel();
}
};
t2.schedule(tt, 10000);
}
}
public class T {
public static void main(String[] args) {
ScheduledExecutorService ses = new ScheduledThreadPoolExecutor(1);
ses.scheduleAtFixedRate(() -> {
System.out.println("hello");
}, 5, 1, TimeUnit.SECONDS);
}
}
6、 TimeUnit时间颗粒工具类
TimeUnit是java.util.concurrent包下面的一个类,表示给定单元粒度的时间段
-
主要作用
时间颗粒度转换
延时
-
常用的颗粒度
TimeUnit.DAYS // 天
TimeUnit.HOURS // 小时
TimeUnit.MINUTES // 分钟
TimeUnit.SECONDS // 秒
TimeUnit.MILLISECONDS // 毫秒
TimeUnit.NANOSECONDS // 毫微秒
TimeUnit.MINCROSECONDS // 微秒
public long toMillis(long d) // 转换成毫秒
public long toSeconds(long d) // 转换成秒
public long toMinutes(long d) // 转换成分钟
public long toHours(long d) // 转换成小时
public long toDays(long d) // 转换成天
try{
TimeUnit.DAYS.sleep(10);
} catch(InterruptedException e){
throw new RuntimeException(e);
}
try{
Thread.sleep(10000);
} catch(Exception e){
e.printStackTrace();
}