Category Archives: Java

Socket通讯的简单实现与应用(文件上传)

Socket通讯的基本实现

package com.yusian.socket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketDemo {
    public static void main(String[] args) {
        // 服务端进程
        new Thread(() -> {
            try {
                // 创建一个Socket服务
                ServerSocket ss = new ServerSocket(8080);
                // 获取Socket的字节输入流对象,此时程序会阻塞在这个位置,直到有数据
                InputStream is = ss.accept().getInputStream();
                int data = 0;
                // 将接收到的数据输出到控制台
                while ((data = is.read()) != -1) {
                    System.out.print((char) data);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();

        // 客户端进程
        new Thread(() -> {
            try {
                // 创建一个Socket客户端,连接到指定服务器
                Socket s = new Socket("localhost", 8080);
                // 获取Socket的字节输出流,将数据从这里发出
                OutputStream os = s.getOutputStream();
                os.write("Hello Socket...".getBytes());
                // 注意:要主动结束数据发送,否则对方会一直处于等待状态
                s.shutdownOutput();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }
}

[……]

继续阅读

Java中IO流的相关操作

1 字节流

FileInputStreamFileOutputStream

        // IO流的读取与写入
        private static void demo01() throws IOException {
        // 如果是追加内容,则使用第二个参数为true的重载构造函数
        FileOutputStream fos = new FileOutputStream("1.txt");
        fos.write(97);
        fos.write(98);
        fos.write(99);
        fos.close();

        FileInputStream fis = new FileInputStream("1.txt");
        // 字节读取返回的是读取的字节十进制值,并且自动向后偏移,如果返回-1则表过读取完毕
        int data = fis.read();
        System.out.println((char) data);
        fis.close();

        // 一次读取多个字节
        FileInputStream fis2 = new FileInputStream("1.txt");
        int length = 0;
        byte[] bytes = new byte[1024];
        while((length = fis2.read(bytes)) != -1) {
            System.out.print(new String(bytes, 0, length));
        }
        fis2.close();
    }

2 字符流

FileReaderFileWrite

        // 字符流的读取与写入
    private static void demo02() throws IOException {
        // 如果是追加,则第二个参数传true
        FileWriter fw = new FileWriter("1.txt");
        fw.write(new char[]{'中', '国'});
        // 字符的写入是先保存在内存缓存区,需要调用flush方法才会真正的写入到文件
        fw.flush();

        // 单个字符读取
        FileReader fr = new FileReader("1.txt");
        // 文件的读取会以字符的单位一个一个读取,如果返回值为-1则表示读取完毕
        int c = fr.read();
        System.out.println((char) c);

        // 一次读取多个字符
        FileReader fr2 = new FileReader("1.txt");
        int length = 0;
        char[] charArray = new char[1024];
        while((length = fr2.read(charArray)) != -1) {
            System.out.print(new String(charArray, 0, length));
        }
        fr2.close();
    }

3 异常处理

关于换行符号
[……]

继续阅读

线程间通讯之【生产者&消费者】模型

  • 同步:线程间通讯要确保同步执行;
  • 同锁:线程间同步机制锁需要是同一个对象,才能保证同步,可以通过synchronized关键字或Lock来实现;
  • 轮询:通过while或其他循环方法来获取当前状态,是该等待还是通知对方;
  • 通讯:所谓的通讯其实是通过共用锁的waitnotify方法来实现的;

商品对象类

/**
 * 商品描述类,当前只是简单地标记商品的有与无
 */
public class Goods {
    // 是否还有库存
    boolean isEmpty;

    public Goods() {
        this.isEmpty = true;
    }
}

消费者

/**
 * 消费者模型
 */
public class Consumer extends Thread {
    Goods goods;

    public Consumer(Goods goods) {
        this.goods = goods;
    }

    @Override
    public void run() {
        // 循环检测
        while (true) {
            // 同步执行
            synchronized (goods) {
                // 如果库存不为空则开始消费,消费结束后,将库存标记为空
                if (!goods.isEmpty) {
                    System.out.println("---------------------");
                    System.out.println("消费");
                    try {
                        Thread.sleep(1000);
                        System.out.println("...");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("需求");
                    goods.isEmpty = true;
                }
                // 通知生产,当前线程等待,直接到生产唤醒
                goods.notify();
                try {
                    goods.wait();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

生产者
[……]

继续阅读

Java多线程中的线程安全问题

多个线程访问共享数据就会产生冲突的问题,以卖票为例,多个窗口卖同一批票就会出现重复卖的问题

  public static void main(String[] args) {
      Runnable runnable = new Runnable() {
          Integer tickets = 100;
          @Override
          public void run() {
              String name = Thread.currentThread().getName();
              while(tickets-- > 0) {
                  try {
                      Thread.sleep(1);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  System.out.println(name + "正在卖票: " + tickets);
              }
          }
      };
      new Thread(runnable).start();
      new Thread(runnable).start();
      new Thread(runnable).start();
  }

解决方案一:使用同步机制,共享部分同步执行则不会出现重复操作问题

  1. synchronized关键字实现代码块同步
    public static void main(String[] args) {
        Object lock = new Object();
        Runnable runnable = new Runnable() {
            Integer tickets = 100;
    
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                while (true) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock) {
                        if (tickets <= 0) break;
                        System.out.println(name + "正在卖票: " + tickets);
                        tickets--;
                    }
                }
            }
        };
        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
    
  2. synchronized同步方法实现同步机制
    static Integer tickets = 100;
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    sellTicked();
                    if (tickets <= 0) break;
                }
            }
        };
        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
    
    synchronized private static void sellTicked() {
        if (tickets <= 0) return;
        String name = Thread.currentThread().getName();
        System.out.println(name + "正在卖票: " + tickets);
        tickets--;
    }
    

解决方案二:使用锁ReentrantLock
[……]

继续阅读