【Java】网络联机

客户端发起socket连接请求

Socket socket = new Socket(服务器IP地址,TCP端口)
客户端通过建立socket来连接服务器。
socket连接的建立,代表客户端与服务端之间都存有对方的信息,包括IP地址和TCP端口。

TCP端口

TCP端口不是实际的物理端口,是逻辑端口,用来表示不同应用程序的服务。
一台服务器上有65536个端口(0~65535)。
其中,0~1023这些TCP端口是保留给已知的特定的服务使用,比如,HTTP服务是80端口,Telnet服务是23端口,SMTP服务是25端口。

客户端和服务端的通信

客户端与服务端的应用程序通过socket建立连接。

//Client.java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;

public class Client {
    public void go(){
        try {
            Socket socket = new Socket("127.0.0.1",5000);
            InputStreamReader stream = new InputStreamReader(socket.getInputStream());
            BufferedReader reader = new BufferedReader(stream);
            String s = reader.readLine();
            System.out.println("s is "+s);
            reader.close();

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        Client c = new Client();
        c.go();
    }
}
//Server.java
import java.io.IOException;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    public void go(){
        try {
            ServerSocket serverSocket = new ServerSocket(5000);
            while(true){
                Socket socket = serverSocket.accept();
                PrintWriter writer = new PrintWriter(socket.getOutputStream());

//                String s = "hello world";
                String s = "hahahahaha";
                writer.println(s);
                writer.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args){
        Server server = new Server();
        server.go();
    }
}

在这里插入图片描述
在这里插入图片描述
以上,服务器只连接了一个客户端,如果有多个客户端呢?

多线程

线程是独立的线程,代表独立的执行空间。
每个Java应用程序都会有一个主线程,即main()
java.lang.Thread是表示一个线程的类,要启动一个新线程,就要创建一个Thread实例。
Thread实例会有一个任务,线程一启动就会去执行这个任务。
线程的任务是实现Runnable接口的实例。
Runnable接口只有一个方法: run(),线程一启动,就会执行run方法。

//MyRunnable.java
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("running in a new thread");
    }
}
//Test.java
public class Test {
    public static void main(String[] args){
        MyRunnable runnableJob = new MyRunnable();
        Thread myThread = new Thread(runnableJob);
        myThread.start();
        System.out.println("running in main thread");
    }
}

在这里插入图片描述
有时候 主线程的“running in main thread”会先打印,有时候 新线程的“running in a new thread”会先打印。
注意哈,线程调度器决定哪个线程跑哪个线程停,但不会保证任何执行时间和顺序。

  • void start()
    启动线程
  • void join()
    连接线程
  • static void sleep()
    让线程闲置

继续看个例子来了解下 线程调度器这位大哥。

//Test.java
public class Test implements Runnable {
    public static void main(String[] args){
        Runnable test = new Test();
        Thread a = new Thread(test);
        a.setName("threadA");
        Thread b = new Thread(test);
        b.setName("ThreadB");
        a.start();
        b.start();
    }

    @Override
    public void run() {
        for(int i=0;i<5;i++){
            System.out.println(Thread.currentThread().getName());
        }
    }
}

在这里插入图片描述
瞧,线程调度器决定了谁跑谁停,我们可左右不了。

让线程小睡会儿
//MyRunnable.java
public class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("running in a new thread");
    }
}
//Test.java
public class Test {
    public static void main(String[] args){
        MyRunnable runnableJob = new MyRunnable();
        Thread myThread = new Thread(runnableJob);
        myThread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("running in main thread");
    }
}

在这里插入图片描述

并发性问题

多线程可能产生并发性问题,即两个或两个以上线程同时对某个单一对象的数据进行存取。

//BankAccount.java
public class BankAccount {
    private int balance = 100;
    public int getBalance(){
        return balance;
    }
    public void withdraw(int amount){
        balance = balance - amount;
    }
}
//JohnAndLilyJob.java
public class JohnAndLilyJob implements Runnable{
    public BankAccount account = new BankAccount();
    public static void main(String[] args){
        JohnAndLilyJob job = new JohnAndLilyJob();
        Thread a = new Thread(job);
        a.setName("John");
        Thread b = new Thread(job);
        b.setName("Lily");
        a.start();
        b.start();
    }
    @Override
    public void run() {
        for(int i=0;i<5;i++){
            makeWithdraw(20);
            System.out.println("当前余额:"+account.getBalance());
            if(account.getBalance()<0){
                System.out.println("已超支!"+ Thread.currentThread().getName()+" 无法提款");
            }
        }
    }
    public void makeWithdraw(int amount){
        if(account.getBalance()>=amount){
            System.out.println(Thread.currentThread().getName()+" 准备提款");
            try {
                System.out.println(Thread.currentThread().getName()+" 即将入睡");
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+" 已经醒来");
            account.withdraw(amount);
            System.out.println(Thread.currentThread().getName()+" 完成提款");
            System.out.println("当前余额:"+account.getBalance());
        }else{
            System.out.println("当前余额:"+account.getBalance());
            System.out.println("余额不足!" + Thread.currentThread().getName()+" 无法提款");
        }

    }
}

在这里插入图片描述

synchronized防止两个线程同时进入同一对象的同一方法

使用关键词synchronized修改方法makeWithdraw,使得该方法仅可被单一线程调用。

 public synchronized void makeWithdraw(int amount){
     if(account.getBalance()>=amount){
         System.out.println(Thread.currentThread().getName()+" 准备提款");
         try {
             System.out.println(Thread.currentThread().getName()+" 即将入睡");
             Thread.sleep(500);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
         System.out.println(Thread.currentThread().getName()+" 已经醒来");
         account.withdraw(amount);
         System.out.println(Thread.currentThread().getName()+" 完成提款");
         System.out.println("当前余额:"+account.getBalance());
     }else{
         System.out.println("当前余额:"+account.getBalance());
         System.out.println("余额不足!" + Thread.currentThread().getName()+" 无法提款");
     }
 }

每个Java对象都有一把锁,这把锁只有一把钥匙。
当对象具有同步化方法时,线程只有取得对象的锁的钥匙后才能进入同步化方法。
对象就算有多个同步化方法,也还是只有一个锁。一旦某个线程进入该对象的某个同步化方法,那么其他线程就无法进入该对象的任何同步化方法。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值