老师,这个自动拆箱、装箱中的编译器,是指jdk吗?jdk不是集成开发工具吗?或者说是IEDA?
老师好,请问容器一般是在什么情况下使用的
老师,我不太明白,
finally{ try{ if(bis != null){ bis.close(); } } }
当中,为什么bis != null 时才可以关闭这个流?不等于空不应该是说明这个流里有东西,所以更不应该关闭才对吗
为什么有的类中private定义的成员变量有其get方法,有的没有?
class Manager{ private String name; public Manager(String name){ this.name=name; } public String getName(){ return this.name; } class SaleMan{ private String name; public SaleMan(String name){ this.name=name; }
老师,是不是因为private限定了该属性只能被本类访问,所以在反射的时候不能通过安全检查
老师,一对多聊天服务中,我的客户端不是每次都能返回消息。
下面的是服务端的代码
package com.bjsxt.ls.网络编程.TCP.一对多聊天服务器; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; //创建服务端接收消息的线程 class ChatReceive extends Thread{ private Socket ss; public ChatReceive(Socket n){ this.ss=n; } @Override public void run() { this.receive1(); } //创建接收消息的线程 public void receive1(){ BufferedReader br =null; try { br = new BufferedReader(new InputStreamReader(this.ss.getInputStream())); while (true){ String jieshou = br.readLine(); synchronized ("同步锁") { //要让发送消息和接收消息的线程处于同步状态,需要在两个线程上加上同一个名字的对象锁 ChatServer.BUF = jieshou; //将接收到的消息保存到缓存区 "同步锁".notify(); //当消息存到缓存区之后,唤醒发送消息线程,可以发送消息了 } } } catch (IOException e) { e.printStackTrace(); }finally { if (br != null){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if (this.ss != null){ try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } } } //创建服务端发送消息的线程类 class ChatSend extends Thread{ private Socket ss; public ChatSend(Socket n){ this.ss=n; } @Override public void run() { this.send1(); } //创建发送消息的方法 public void send1(){ PrintWriter pw = null ; try { pw = new PrintWriter(this.ss.getOutputStream()); while (true) { synchronized ("同步锁") { //要让发送消息和接收消息的线程处于同步状态,需要在两个线程上加上同一个名字的对象锁 "同步锁".wait(); //发送消息的线程应先处于等待状态 pw.println(ChatServer.BUF); //将消息从缓存区取出,因为BUF是static的,直接用类名就能调用 pw.flush(); } } } catch (Exception e) { e.printStackTrace(); }finally { if (pw != null){ pw.close(); } if (this.ss != null){ try { this.ss.close(); } catch (IOException e) { e.printStackTrace(); } } } } } //主线程用于启动服务端,客户端可以使用之前的“点对点优化”中的GoodP2P public class ChatServer { //定义一个字符串类型的缓存区 public static String BUF; public static void main(String[] args) { System.out.println("正在启动服务器....."); System.out.println("<HappyDay>聊天室启动"); ServerSocket serverSocket = null; try { serverSocket =new ServerSocket(332); while (true){ Socket sk =serverSocket.accept(); //将启动服务端放在循环中,因为每次发送或接收消息都需要启动服务端 System.out.println("已经连接到IP地址为["+ InetAddress.getLocalHost() +"]的主机。"); new ChatReceive(sk).start(); //启动线程 new ChatSend(sk).start(); } } catch (IOException e) { e.printStackTrace(); }finally { if(serverSocket!=null){ try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
这个是用的优化的点对点聊天作为客户端的代码
package com.bjsxt.ls.网络编程.TCP.点对点优化; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; //创建发送消息线程 class send1 extends Thread{ private Socket socket =null; private Scanner scanner =null; public send1(Socket s1,Scanner s2){ this.socket =s1; this.scanner=s2; } //创建发送消息的方法 public void sengmessage(){ PrintWriter pw =null; try{ pw =new PrintWriter(socket.getOutputStream()); scanner = new Scanner(System.in); while (true){ String say =scanner.nextLine(); pw.println(say); pw.flush(); } }catch (Exception e){ e.printStackTrace(); }finally { if (pw != null){ pw.close(); } if (scanner != null){ scanner.close(); } if (socket != null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public void run() { this.sengmessage(); } } //创建接收消息的线程 class receive extends Thread{ private Socket socket =null; public receive(Socket x){ this.socket = x; } public void receivemessage(){ BufferedReader br= null; try { br = new BufferedReader(new InputStreamReader(socket.getInputStream())); while (true){ String rs = br.readLine(); System.out.println("收到的消息是:"+rs); } } catch (IOException e) { e.printStackTrace(); }finally { if (br != null){ try { br.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket!= null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Override public void run() { this.receivemessage(); } } public class GoodP2P { public static void main(String[] args) { Scanner scanner = null; ServerSocket serverSocket = null; Socket socket = null; scanner =new Scanner(System.in); System.out.println("请输入:server,<port> 或者:" + "<ip>,<port>"); String str = scanner.nextLine(); String arr[] =str.split(",");//以逗号为分割点存入数组 //判断当输入的server时,启动服务端 if ("server".equals(arr[0])){ System.out.println("TCP点对点通信,正在启动服务端,连接端口号["+arr[1]+"]"); try { serverSocket =new ServerSocket(Integer.parseInt(arr[1]));//将字符串强转为整型 socket = serverSocket.accept(); } catch (IOException e) { e.printStackTrace(); } System.out.println("连接成功!"); } //当输入的不是server时,即进入客户端 else { try { socket = new Socket(arr[0],Integer.parseInt(arr[1])); System.out.println("连接成功!"); } catch (IOException e) { e.printStackTrace(); } } //启动发送消息的线程 new send1(socket,scanner).start(); new receive(socket).start(); if (serverSocket != null){ try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
下面的运行的截图:
服务端测试
客户端1
客户端2
客户端3
老师,既然控制台上输入了server,那么就是进入了启动服务端的线程。那客户端又是怎么启动的呢?客户端不是放在else中了嘛,选了server那么else里面的内容就不会执行了呀,那客户端也不会启动了呀。我有点不理解这里,请老师解答一下。
我这个问题是在哪?
/** * 账户类 */ class Account{ private String accountNum;//账户 private double balance;//余额 public Account(){ } public Account(String accountNum, double balance) { this.accountNum = accountNum; this.balance = balance; } public String getAccountNum() { return accountNum; } public void setAccountNum(String accountNum) { this.accountNum = accountNum; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } } class DrawMoney extends Thread{ private Account account;//账户对象 private double drawMoney;//取款金额 public DrawMoney(String name,Account account,double drawMoney){ super(name); this.account=account; this.drawMoney=drawMoney; } /** * 取款线程 */ @Override public void run() { if (this.account.getBalance()>=this.drawMoney){ System.out.println(this.getName()+"取钱成功 "+this.drawMoney); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } this.account.setBalance(this.account.getBalance()-this.drawMoney); System.out.println("\t 余额为:"+this.account.getBalance()); }else { System.out.println(this.getName()+"取钱失败"); } } } public class DrawMoneyThread { public static void main(String[] args) { Account account=new Account("1234",1000); new DrawMoney("小王",account,800).start(); new DrawMoney("李梅",account,500).start(); } }
老师,这个线程并发为什么不需要像生产者消费者模型一样,用一个缓冲区来缓存消息呢?
pw = new PrintWriter(socket.getInputStream)为什么这个时候,不要将socket.getInputStream转化成字符,是PrintWriter自动能将字节流转换成字符流嘛?
老师,判断放馒头和取馒头线程是否等待,不用if语句而用while语句还是不同明白,能解释一下吗?
老师,之前这版块不是到十三章“手写服务器”的吗?为什么没有了的?
map.get(u)值返回为null,而不是我put的值。但是我用比较器进行比较,结果又是正常的。
public class TreeMapTest { public static void main(String[] args) { Map<Users,String> map = new TreeMap<>(); Users u1 = new Users("小a",18); Users u2 = new Users("小b",5); Users u3 = new Users("小c",9); String value = map.put(u1,"a"); System.out.println(value); System.out.println(map.get(u1)); map.put(u2,"b"); map.put(u3,"c"); Set<Users> keys = map.keySet(); for(Users u: keys){ System.out.println(u+"--- "+map.get(u)); } } } public class Users implements Comparable<Users>{ private String uname; private int uage; public String getUname() { return uname; } public void setUname(String uname) { this.uname = uname; } public int getUage() { return uage; } public void setUage(int uage) { this.uage = uage; } public Users(String uname, int uage) { this.uname = uname; this.uage = uage; } public Users() { } //如果大于返回1,小于返回-1 ,相等返回0 @Override public int compareTo(Users o) { if(this.uage > o.uage){ return 1; }else{ return -1; } } @Override public String toString() { return "Users{" + "uname='" + uname + '\'' + ", uage=" + uage + '}'; } }
package com.bjsxt.ls.DuoXianCheng.线程并发; /* 线程并发:生产者和消费者模型 定义一个做馒头和取馒头的类,中间有一个缓冲区。做好的馒头放入缓冲区,取馒头从缓冲区取。 假设缓冲区容量是10,那么当做了十个馒头的时候,做馒头线程就要停止(阻塞)。当缓冲区没有馒头的时候,取馒头线程就要停止(阻塞)。 但是当做馒头线程放入馒头的时候,就要用notify提醒取馒头线程,不要一直处于阻塞状态; 同样当取馒头线程拿馒头的时候,也要提醒做馒头线程要做馒头,不要一直处于阻塞状态; */ //定义馒头类 class ManTou{ private int id; public ManTou(int id) { this.id = id; } public int getId() { return id; } } //定义缓冲区,用数组来存放馒头 class resitor{ private ManTou[] arr =new ManTou[10]; //创建一个长度为10,类型为ManTou的数组 private int index; //定义索引 //定义做馒头方法 //因为做馒头和取馒头都是对同样对象进行操作,所以这两个状态是要互斥,即同步的。所以要用synchronized使得这两个状态处于同步状态 //synchronzied放在方法名上相当于将synchronized(this){}将方法体包裹起来。 public synchronized void makeMantou(ManTou manTou){ //用while做出判断,如果当数组满的时候,就要用wait方法,使得此线程进入阻塞状态,不再生产馒头了; while (this.index == this.arr.length){ try { wait(); /*wait属于Object类只能用在synchronized块中。 此方法执行之后,在本方法所在的对象锁会被阻塞, 其他需要该对象锁的线程就可以继续运行了。*/ } catch (InterruptedException e) { e.printStackTrace(); } } //notify也属于Object类 this.notify();//当放入馒头的时候,要用notify唤醒取馒头的线程,以防拿馒头线程处于阻塞状态 。 //该方法会唤醒处于等待状态队列中的一个线程 this.arr[this.index]=manTou; index++; } //定义取馒头方法 public synchronized ManTou takeMantou(){ //用while判断,当索引为0,即缓冲区没有馒头的时候,就用wait阻塞此状态,不要再去取馒头了; while (this.index==0){ try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } this.notify();//拿馒头的时候也要唤醒做馒头的线程,以防处于阻塞状态不做馒头了。 this.index--; return this.arr[this.index]; } } //创建做馒头线程 class makeThread extends Thread{ private resitor r; //定义一个类型是resitor的变量r public makeThread(resitor r){ this.r = r; } @Override public void run() { for (int i=1;i<11;i++){ System.out.println("生成第"+i+"个馒头"); ManTou manTou =new ManTou(i); this.r.push(manTou); } } } //创建取馒头线程 class takeThread extends Thread{ private resitor r; //定义一个类型是resitor的变量r public takeThread(resitor r){ this.r = r; } @Override public void run() { for (int i=1;i<11;i++){ ManTou manTou =this.r.pop(); System.out.println("拿走第"+i+"个馒头"); } } } public class ProducerThread { public static void main(String[] args) { resitor tt =new resitor(); new makeThread(tt).start(); new takeThread(tt).start(); } }
老师这是什么原因造成的?
老师,this 、字符串、Class、自定义这几个对象锁,分别都应该在什么情况下使用?
非常抱歉给您带来不好的体验!为了更深入的了解您的学习情况以及遇到的问题,您可以直接拨打投诉热线:
我们将在第一时间处理好您的问题!
关于
课程分类
百战程序员微信公众号
百战程序员微信小程序
©2014-2025百战汇智(北京)科技有限公司 All Rights Reserved 北京亦庄经济开发区科创十四街 赛蒂国际工业园网站维护:百战汇智(北京)科技有限公司 京公网安备 11011402011233号 京ICP备18060230号-3 营业执照 经营许可证:京B2-20212637