1.连接网络
网络运行的底层细节已经都由java.net函数库处理了
传送与接收网络上的数据只不过是链接上不同串流的输入与输出
客户端工作需要3件事
1.客户端与服务器建立初始链接
//socket链接代表两台机器存有对方的信息 地址+端口号
Socket chatSocket = new Socket( "192.168.0.110", "5000" );
端口是一个16位宽用来识别服务器上特定程序的数字,不同的程序不能使用同一个端口(绑定会收到BingException)
2.如何传送信息到服务器
使用PrintWrite 是字符和字节之间转换的桥梁
PrintWriter writer = new PrintWriter( chatSocket.getOutputStream() );
writer.println( "hello" );
writer.print( "world!" );
3.如何从服务器接收信息
使用BufferReader InputStreamReader是沟通字节流和字符流的桥梁
InputStreamReader stream = new InputStreamReader( chatSocket.getInputStream() );
//缓冲区BufferReader
BufferedReader reader = new BufferedReader( stream );
String Message = reader.readLine();
简单的客户端程序
import java.io.*;
import java.net.*;
public public class DailyAdvice {
public void go(){
try {
Socket s = new Socket( "192.168.0.110", 5555 );
InputStreamReader stream = new InputStreamReader( s.getInputStream() );
BufferedReader reader = new BufferedReader( stream );
String advice = reader.readLine();
System.out.println( advice );
} catch (IOException ex) {
ex.printStackTrace();
}
}
public static void main( String[] args){
DailyAdvice client = new DailyAdvice();
client.go();
}
}
简单的服务器程序
import java.io.*;
import java.net.*;
public class DailyAdviceServer{
String [] advice = { "11", "22", "33", "44" };
public void go(){
try {
ServerSocket server = new ServerSocket( 5555 );
while (true) {
//阻塞的方法 会一直等到链接上来
Socket sock = server.accept();
PrintWriter writer = new PrintWriter( sock.getOutputStream() );
String adv = giveAdvice();
writer.println(adv);
writer.close();
System.out.println( adv );
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
2.线程
新的线程,一个独立的执行空间(stack)
Thread是Java中用来表示线程的类,要建立线程就需要创建Thread
Thread的方法有 void join(); void start(); static void sleep();
启动新的线程
1.建立Runnable对象(线程的任务) Runnable threadJob = new MyRunableJob(); //接口的作用
Runnable这个接口只有一个方法 public void run();
2.建立Thread对象(执行者) 并把任务给Thread //相当于给Thread取得run的方法
Thread myThread = new Thread( threadJob );
3.启动Thread
myThread.start(); //线程启动后回吧Runnable对象放到新的执行空间
线程的run();方法执行完毕线程就不能再重新启动,Thread对象还在堆上但是已经失去了线程的执行性,只剩对象本身
一旦线程进入可执行状态,他就会在可执行与不可执行两种状态中来来回回,同时也会有另一种状态,暂不可执行状态
让线程小睡一下 //有可能抛出InterruptedException 需要try/catch
try {
Thread.sleep( 2000 );
} catch (InterruptedException) {
ex.printStackTrace();
}
建立与启动多个线程
public class RunThreads implements Runnable{
public static void main( String[] args){
RunThreads runner = new RunThreads();
Thread alpha = new Thread( runner );
Thread beta = new Thread ( runner );
alpha.setName( " Alpha thread"); //给线程取名字,便于调试
beta.setName( "beta Thread" );
//启动线程
alpha.start();
beta.start();
}
public void run(){
for( int i=0; i < 25; i++){
String threadName = Thread.currentThread().getName();
System.out.println( threadName + " is Running!" );
}
}
}
3.线程的安全性问题
1.线程的并发问题
两个或则两个以上的线程存取单一对象的数据导致的数据错误问题
使用synchronized这个关键词来修饰方法,使得每次只能被单一的线程存取
synchronized 代表线程需要一把钥匙来存取被同步化过的线程,要保护数据就把作用在数据上的方法同步化(锁住的是存取数据的方法而不是数据)
锁其实是配在对象上的,每个Java对象都有一把锁,每个锁只有一个钥匙(就算对象有多个同步化方法,对象也只有一个锁)
小心死锁问题 只要连个线程和两个对象就可以造成死锁问题
public synchronized void increment(){
int i = balance;
balance = i+1;
}
类的锁
静态变量的保护, 如果静态的方法可以对静态的变量做更新
对于被载入的每个类也有个锁,如果你要对静态的方法做同步化时会使用类本身的锁