day19

先瞄准再开枪發表於2024-10-19

執行緒組

執行緒組:將屬於同一類的執行緒劃分到同一組中,可以直接對執行緒組進行設定。

    ThreadGroup
        構造方法:
            ThreadGroup(String name) 構造一個新的執行緒組。
class MyThread1 extends Thread{
    public MyThread1() {
    }

    public MyThread1(ThreadGroup group, String name) {
        //父類的構造方法Thread(ThreadGroup group, String name)
        super(group, name);
    }

    @Override
    public void run() {
        System.out.println("這是帥哥執行緒");
    }
}
//建立執行緒組,組名自定義
        ThreadGroup tg1 = new ThreadGroup("帥哥組");
        ThreadGroup tg2 = new ThreadGroup("美女組");


        //建立多個執行緒物件,分配到執行緒組中
//        MyThread1 t1 = new MyThread1();
//        t1.setName("李剛");
        //Thread(ThreadGroup group, String name)
        //分配一個新的 Thread物件。
        MyThread1 t1 = new MyThread1(tg1, "李剛");
        MyThread1 t2 = new MyThread1(tg1, "錢志強");
        MyThread1 t3 = new MyThread1(tg2, "李世博");
        MyThread1 t4 = new MyThread1(tg2, "楊珊珊");

執行緒池:ThreadPool

Executors:
    static ExecutorService newCachedThreadPool() 建立一個根據需要建立新執行緒的執行緒池,但在可用時將重新使用以前構造的執行緒。
    static ExecutorService newFixedThreadPool(int nThreads) 建立一個執行緒池,該執行緒池重用固定數量的從共享無界佇列中執行的執行緒。
    static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) 建立一個執行緒池,可以排程命令在給定的延遲之後執行,或定期執行。
public class ThreadPoolDemo1 {
    public static void main(String[] args) {
        //建立一個固定大小的執行緒池
        ExecutorService pool = Executors.newFixedThreadPool(2);

        //Future<?> submit(Runnable task);
        pool.submit(new MyRunnable());
        pool.submit(new MyRunnable());
        //可用時將重新使用以前構造的執行緒。
        pool.submit(new MyRunnable());
        //建立了一個匿名內部類Callable<Object>的例項,並將其提交給ExecutorService物件pool。這個匿名內部類實現了Callable介面,並覆蓋了call方法
        pool.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                for (int i = 1; i <= 100; i++) {
                    System.out.println(Thread.currentThread().getName() + " - " + i);
                }
                return null;
            }
雖然有四個執行緒但是執行緒池裡實際只有2個執行緒 可用時將重新使用以前構造的執行緒

定時器

/*
    定時器:Timer
    定時任務:TimerTask
 */
public class TimerDemo1 {
    public static void main(String[] args) {
        //建立一個定時器
        Timer timer = new Timer();

        //public void schedule(TimerTask task, long delay) 延遲多少毫秒後執行定義任務
        timer.schedule(new MyTask(timer), 5000);

        //public void schedule(TimerTask task,long delay,long period) 延遲delay毫秒後執行定義任務,後續每間隔period毫米執行一次
        timer.schedule(new MyTask(timer), 5000,2000);
    }
}
class MyTask extends TimerTask{
    Timer timer;

    public MyTask(Timer timer) {
        this.timer = timer;
    }

    @Override
    public void run() {
        System.out.println("砰!爆炸了.....");
//是一個方法呼叫,通常用於取消一個 Timer 物件中已經安排但尚未執行的任務
//        timer.cancel();
    }
}

單例模式

/*
    單例模式:在整個java程式執行期間,記憶體中某一個物件有且僅只能有一個。筆試
        1. 餓漢式 工作開發中 
        2. 懶漢式 面試的時候說,可能會涉及執行緒安全的問題。
/*
    懶漢式 需要再建立
 */
// t1, t2, t3
public class Student2 {
    private static Student2 student2;

    private Student2(){}

    public synchronized static Student2 getStudent2(){
        if(student2==null){
            // t1 , t2, t3
            student2 = new Student2();
        }

        return student2;
    }
}
/*
    餓漢式  在成員變數中建立好
 */
public class Student1 {
    private static Student1 student1 = new Student1();

    private Student1(){}

    public static Student1 getStudent1(){
        return student1;
    }
}
*/
/*
    設計模式:
        建立型模式
            簡單工廠模式
public class AnimalFactory {
    private AnimalFactory() {
    }

    public static Animal createAnimal(String name){
        if("dog".equals(name)){
            return new Dog();
        }else if("cat".equals(name)){
            return new Cat();
        }else {
            System.out.println("沒有該動物");
            return null;
        }
    }
}
            工廠方法模式
public class DogFactory extends AnimalFactory{
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}
            單例模式
        行為型模式
        結構型模式
 */

InetAddress

/*
    InetAddress: java提供的類,用於表示ip地址


 */
public class InetAddressDemo1 {
    public static void main(String[] args) throws Exception {
        // static InetAddress getLocalHost()
        //返回本地主機的地址。
        InetAddress ip1 = InetAddress.getLocalHost();
        System.out.println(ip1);

        // String getHostName()
        //獲取此IP地址的主機名。
        String hostName = ip1.getHostName();
        //String getHostName()
        //獲取此IP地址的主機名。
        String ip = ip1.getHostAddress();
        System.out.println("主機名: "+hostName+", ip地址:"+ip);

    }
}

UDP

udp接收端
/*
    1:建立udp的socket服務.
    2:透過receive方法接收資料
    3:將收到的資料儲存到資料包物件中
    4:透過資料包物件的功能來完成對接收到資料進行解析.
    5:可以對資源進行關閉

 */
public class ReceiveDemo1 {
    public static void main(String[] args) throws Exception{
        // 1:建立udp的socket服務
        DatagramSocket socket = new DatagramSocket(10086);

        // 2:透過receive方法接收資料
        //public synchronized void receive(DatagramPacket p)
        byte[] bytes = new byte[1024];
        DatagramPacket packet = new DatagramPacket(bytes, bytes.length);
        socket.receive(packet);

        //4:透過資料包物件的功能來完成對接收到資料進行解析.
        byte[] data = packet.getData();
        int length = packet.getLength();
        String info = new String(data, 0, length);
        System.out.println("傳送段發來一條訊息:"+info);


        // 5:可以對資源進行關閉
        socket.close();

    }
}
udp傳送端
/*
    1:建立udp的socket服務
    2:將要傳送的資料封裝成資料包
    3:透過udp的socket服務,將資料包傳送出
    4:關閉資源

 */
public class SendDemo1 {
    public static void main(String[] args) throws Exception{
        // 1:建立udp的socket服務
        // DatagramSocket
        //DatagramSocket()
        //構造資料包套接字並將其繫結到本地主機上的任何可用埠。
        DatagramSocket socket = new DatagramSocket();

        // 2:將要傳送的資料封裝成資料包 DatagramPacket
        //DatagramPacket(byte[] buf, int length, InetAddress address, int port)
        //構造用於傳送長度的分組的資料包包 length指定主機上到指定的埠號。
        byte[] bytes = "李剛來了...".getBytes();
        int length = bytes.length;
        InetAddress address = InetAddress.getByName("192.168.22.15");
        DatagramPacket packet = new DatagramPacket(bytes, length, address, 10086);


        // 3:透過udp的socket服務,將資料包傳送出
        //public void send(DatagramPacket p)
        socket.send(packet);

        // 4:關閉資源
        socket.close();

    }
}

TCP

/*
    1:建立伺服器端的socket服務,需要一個埠
    2:服務端沒有直接流的操作,而是透過accept方法獲取客戶端物件,在透過獲取到的客戶端物件的流和客戶端進行通訊
    3:透過客戶端的獲取流物件的方法,讀取資料或者寫入資料
    4:如果服務完成,需要關閉客戶端,然後關閉伺服器,但是,一般會關閉客戶端,不會關閉伺服器,因為服務端是一直提供服務的

 */
    TCP服務端
    public class ServerDemo1 {
        public static void main(String[] args)  throws Exception{
            // 1:建立伺服器端的socket服務,需要一個埠
            //ServerSocket(int port)
            //建立繫結到指定埠的伺服器套接字。
            ServerSocket ss = new ServerSocket(12345);

        while (true){
            // 2:服務端沒有直接流的操作,而是透過accept方法獲取客戶端物件,在透過獲取到的客戶端物件的流和客戶端進行通訊
            Socket socket = ss.accept();

            new TCPThread(socket).start();
        }
    }
}

class TCPThread extends Thread{

    Socket socket;

    public TCPThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        InetAddress inetAddress = socket.getInetAddress();
        String hostName = inetAddress.getHostName();
        System.out.println("使用者:"+hostName+" 已上線! ");

        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\target\\" + hostName + "-" + System.currentTimeMillis() + ".jpg"));
            while (true) {
                // 3:透過客戶端的獲取流物件的方法,讀取資料或者寫入資料
                // 獲取通道中的輸入流
                InputStream inputStream = socket.getInputStream();
                byte[] bytes = new byte[2048];
                int length = 0;
                while ((length = inputStream.read(bytes))!=-1){
                    // 4:透過流的物件可以對資料進行傳輸
                    bos.write(bytes,0, length);
                    bos.flush(); // 來自於通道中的類
                }

                // 獲取通道中的輸出流
                OutputStream outputStream = socket.getOutputStream();
                outputStream.write("圖片已上傳!!".getBytes());
                outputStream.flush();
            }
        }catch (Exception e){
            System.out.println("-----------------------");
            System.out.println(hostName+" 使用者已下線....");
            System.out.println("-----------------------");
        }
    }
}
TCP客戶端
/*
    1:建立客戶端的Socket服務,並明確要連線的伺服器。
    2:如果連線建立成功,就表明,已經建立了資料傳輸的通道.就可以在該通道透過IO進行資料的讀取和寫入.該通道稱為Socket流,Socket流中既有讀取流,也有寫入流.
    3:透過Socket物件的方法,可以獲取這兩個流
    4:透過流的物件可以對資料進行傳輸
    5:如果傳輸資料完畢,關閉資源

 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception {
        // 1:建立客戶端的Socket服務,並明確要連線的伺服器。
        //Socket(String host, int port)
        //建立流套接字並將其連線到指定主機上的指定埠號。
        Socket socket = new Socket("192.168.22.24", 12345);
        Scanner sc = new Scanner(System.in);



        // 3:透過Socket物件的方法,可以獲取這兩個流
        //獲取通道中的輸出流,將資料傳送給服務端
        OutputStream outputStream = socket.getOutputStream();
        //獲取通道中的輸入流
        InputStream inputStream = socket.getInputStream();

        // E:\\李剛的物件.jpg
        BufferedInputStream bis = null;
        while (true){
            try {
                System.out.print("請輸入要上傳檔案的路徑:");
                String address = sc.nextLine();
                bis = new BufferedInputStream(new FileInputStream(address));
                break;
            }catch (Exception e){
                System.out.println("路徑不存在!重新輸入!");
            }
        }
        if(bis!=null){
            byte[] bytes = new byte[2048];
            int length = 0;
            while ((length = bis.read(bytes))!=-1){
                // 4:透過流的物件可以對資料進行傳輸
                outputStream.write(bytes,0, length);
                outputStream.flush(); // 來自於通道中的類
            }
        }

        //關閉輸出流,通知服務端讀取結束
        socket.shutdownOutput();

        // 接收服務端的反饋
        byte[] bytes = new byte[1024];
        int length = inputStream.read(bytes);
        String s = new String(bytes, 0, length);
        System.out.println(s);


        // 5:如果傳輸資料完畢,關閉資源
//        outputStream.close();
        socket.close();

    }
}

UDP和TCP區別

TCP:是一種面向連線的協議,它在資料傳輸開始之前需要建立一個連線,確保資料傳輸的可靠性,傳輸較慢。
UDP:是一種無連線的協議,它不需要建立連線就可以直接傳送資料,傳輸快。