新手初学Java网络编程


Posted in Java/Android onJuly 07, 2021
目录
  • 运行线程
    • 回调
    • 同步方法
    • 同步块
    • 死锁
    • 优先级
    • 暂停
      • 可以对IO阻塞
      • 可以对同步对象阻塞
      • 可以放弃
      • 可以休眠
      • 可以连接另一个线程
      • 可以等待一个对象
      • 可以结束
    • 可以被更高优先级线程抢占
  • 总结

 

运行线程

创建Thread的子类

public class ThreadChild extends Thread {
    @Override
    public void run() {
        while (true) {
            System.out.println("run");
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        ThreadChild t = new ThreadChild();
        t.start();
    }
}

创建Thread传入Runnable接口实现类

public class RunnableImpl implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("run");
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t = new Thread(new RunnableImpl());
        t.start();
    }
}

 

回调

ExecutorService线程池的Submit()可接收Runnable或者Callable.Callable执行结束后有返回值,Runnable执行结束后没有返回值.可以通过submit的返回对象Future的get方法获取返回返回值,需要注意的是get方法是一个阻塞方法.若线程没有执行完毕,则会阻塞get()直到线程执行结束后返回数据.

public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Future<Integer> future = executorService.submit(() -> {
            TimeUnit.SECONDS.sleep( 3);
            return 1;
        });
        Future<?> future2 = executorService.submit(() -> {
        });
        Future<String> future3 = executorService.submit(() -> {
        }, "aaa");
        System.out.println(future.get());
        System.out.println(future2.get());
        System.out.println(future3.get());
    }

 

同步方法

synchronized关键字和方法组合使用后,该方法是一个同步方法。同步方法都有一个隐试的锁,多个线程同时执行该方法时,只能顺序执行,未强到锁的线程处于阻塞状态。另外静态方法和非静态方法使用的是不同的锁,非静态方法的锁是对象锁,若两个线程通过两个该类的对象调用那么互不影响。静态方法是类锁,即本类的Class对象。同步方法无法指定锁资源,要么是this锁,要么是Class锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Test test = new Test();
        Thread t1 = new Thread(()->{
            test.synFunction();
        });
        Thread t2 = new Thread(()->{
            test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public synchronized void synFunction(){
        try {
            System.out.println("-------------");
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e) {}        
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(()->{
            Test.synFunction();
        });
        Thread t2 = new Thread(()->{
            Test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public static synchronized void synFunction(){
        try {
            System.out.println("-------------");
            TimeUnit.SECONDS.sleep(3);
        }catch (Exception e) {}        
    }
}

 

同步块

同步代码块可以指定锁对象,非静态方法可以指定任意的对象锁,或者任意的类锁。但静态方法只能使用任意的类锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Test lock = new Test();
        Thread t1 = new Thread(() -> {
            lock.synFunction();
        });
        Thread t2 = new Thread(() -> {
            lock.synFunction();
        });
        t1.start();
        t2.start();
    }
    public void synFunction() {
        synchronized (this) {//对象锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Test lock1 = new Test();
        Test lock2 = new Test();
        Thread t1 = new Thread(() -> {
            lock1.synFunction(lock1);
        });
        Thread t2 = new Thread(() -> {
            lock2.synFunction(lock2);
        });
        t1.start();
        t2.start();
    }
    public void synFunction(Object lock) {
        synchronized (lock) {//对象锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Test lock1 = new Test();
        Test lock2 = new Test();
        Thread t1 = new Thread(() -> {
            lock1.synFunction();
        });
        Thread t2 = new Thread(() -> {
            lock2.synFunction();
        });
        t1.start();
        t2.start();
    }
    public void synFunction() {
        synchronized (Test.class) {//类锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction();
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction();
        });
        t1.start();
        t2.start();
    }
    public static void synFunction() {
        synchronized (Object.class) {//类锁
            try {
                System.out.println("-------------");
                TimeUnit.SECONDS.sleep(3);
            } catch (Exception e) {
            }
        }
    }
}

 

死锁

当多个线程竞争锁时,可能会导致死锁。一个线程由于没有得到一个锁而阻塞它也不会释放已经获取的锁。方法1获取锁的顺序是Test.class,Object.class。方法2获取锁的顺序是Object.class,Test.class。程序会陷入死锁。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction1();
        });
        Thread t2 = new Thread(() -> {
             Test.synFunction2();
        });
        t1.start();
        t2.start();
    }
    public static void synFunction1() {
        synchronized (Test.class) {// 类锁
            try {
                System.out.println("synFunction1-------------AAAAAAAAAAAAA");
                synchronized (Object.class) {// 类锁
                    try {
                        System.out.println("synFunction1-------------bbbbbbbbbbbbb");
                    } catch (Exception e) {
                    }
                }
            } catch (Exception e) {
            }
        }    
    }
    public static void synFunction2() {
        synchronized (Object.class) {// 类锁
            try {
                System.out.println("synFunction2-------------AAAAAAAAAAAAA");
            } catch (Exception e) {
            }
            synchronized (Test.class) {// 类锁
                try {
                    System.out.println("synFunction2-------------bbbbbbbbbbbbb");
                } catch (Exception e) {
                }
            }
        }
    }
}

 

优先级

不是所有线程创建时都是均等的,每个线程都有一个优先级,指定从0-10的整数。当多个线程运行时,虚拟机通常只运行最高优先级的线程,但这并不是一个严格的规则。在Java中10是最高优先级,0是最低优先级。默认优先级为5.并不是所有操作系统都支持这11个优先级。例如Windows只有7个优先级。优先级(1,2)(3,4)(6,7)(8,9)会做同样的处理。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
             Test.synFunction("bbbbbbbbbb");
        });
        t2.setPriority(9);
        t1.setPriority(1);
        t1.start();
        t2.start();
    }
    public static void synFunction(String name) {
        System.out.println(name+"--------------");
    }
}

 

暂停

为了能让其他线程有机会运行,一个线程有8中方式可以暂停或者指示它准备暂停。

 

可以对IO阻塞

要让网络程序中的线程自动放弃CPU控制权,最常见的方式是IO阻塞。由于CPU比网络和磁盘快的多,网络程序经常会在等待数据从网络到达或向网络发送数据时阻塞。即使只阻塞几毫秒,这一点时间也足够其他线程用来完成重要的任务。

 

可以对同步对象阻塞

线程在进入一个同步方法或代码块时也会阻塞。如果这个线程没有所同步对象的锁,而其他线程拥有这个锁,这个线程就会暂停,直到锁被释放为止。如果这个锁永远不会释放,那么这个线程会永久停止。

 

可以放弃

调用Thread.yield()静态方法可以做到显试的放弃线程控制权,这将通知虚拟机,可以优先执行其他线程。放弃并不会释放这个线程拥有的锁,因此在理想情况下被放弃的线程不要做任何的同步。如果等待运行的其他线程都是因为这个线程所拥有的同步资源而阻塞,那么这些线程将不能运行。实际上,控制权将回到唯一可以运行的线程,即刚刚放弃的这个线程,这很大程度上失去了放弃的意义。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public static void synFunction(String name) {
        for (int i = 0;; i++) {
            Thread.yield();
            System.out.println(name + "--------------" + i);
        }
    }
    public static void synFunction2(String name) {
        for (int i = 0;; i++)
            System.out.println(name + "--------------"+i);
    }
}

 

可以休眠

休眠是更有利的放弃方式。放弃只是表示线程愿意暂停,让其他有相同优先级的线程有机会运行,而进入休眠的线程有所不同,不管有没有其他线程准备运行,休眠线程都会暂停。这样一来,不只是其他有相同优先级的线程会得到机会,还会给较低优先级的线程运行机会。不过进入休眠的线程仍然拥有它已经获得得所有锁。因此其他需要相同锁得线程依然会阻塞,要避免在同步方法或块内让线程休眠。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public synchronized static void synFunction(String name) {
        try {
            System.out.println(name);
            Thread.sleep(1000 * 10);
        } catch (Exception e) {
        }
    }
    public synchronized static void synFunction2(String name) {
        System.out.println(name);
    }
}
package com.datang.bingxiang.demo;
import java.util.concurrent.TimeUnit;
public class Test {
    public static void main(String[] args) throws Exception {
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa");
        });
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        t1.start();
        t2.start();
    }
    public synchronized static void synFunction(String name) {
        try {
            System.out.println(name);
            Thread.sleep(1000 * 3, 999999);//3000毫秒+999999毫秒(第二个参数不能超过999999,也就是不能超过1毫秒)
        } catch (Exception e) {
            System.out.println(e);
        }
    }
    public synchronized static void synFunction2(String name) {
        System.out.println(name);
    }
}

 

可以连接另一个线程

连接线程(既调用join()方法得线程A)等待被连接的线程(join()方法所属的线程对象B)执行完毕后才会执行。在A线程调用B线程的join()A线程会等待B线程执行结束后才会继续执行。要注意的是A线程并不会释放已经获取的锁资源。

public class Test {
    public static void main(String[] args) throws Exception {
        Thread t2 = new Thread(() -> {
            Test.synFunction2("bbbbbbbbbb");
        });
        Thread t1 = new Thread(() -> {
            Test.synFunction("aaaaaaaaaaa",t2);
        });
        
        t1.start();
        t2.start();
    }
    public  static void synFunction(String name,Thread t) {
        try {
            t.join();
            //t.join(1000);
            //t.join(1000,999999);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(name);
        }
    }
    public  static void synFunction2(String name) {
        try {
            Thread.sleep(1000*3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 5; i++) {
            System.out.println(name);
        }
    }
}

 

可以等待一个对象

线程可以等待一个它锁定的对象.在等待时,它会释放这个对象的锁并暂停,直到它得到其他线程的通知.另一个线程以某种方式修改这个对象,通知等待对象的线程,然后继续执行.等待会暂停执行,直到一个对象或资源到达某种状态.实际上,要等待某个特定的对象,希望暂停的线程首先必须使用synchronized获得这个对象的锁,然后调用这个对象的三个重载wait()方法之一.

public class Demo {
    public static void main(String[] args) throws Exception {
        Demo d = new Demo();
        Thread t1 = new Thread(() -> {
            d.a();
        });
        Thread t2 = new Thread(() -> {
            d.b();
        });
        t1.start();
        t2.start();
    }
    boolean flag = true;
    public synchronized void a() {
        try {
            while (true) {
                if (flag) {
                    System.out.println("执行AAAAAAAAAAA");
                    flag = false;
                } else {
                    wait();//等待,不限制等待时间
                    //wait(1000);//等待指定的时间,没有被notify唤醒也可以自己退出等待
                    //wait(1000,999999);//毫秒+纳秒的等待时间
                }
                notify();
            }
        } catch (Exception e) {
        }
    }
    public synchronized void b() {
        try {
            while (true) {
                if (!flag) {
                    System.out.println("执行BBBBBBBBBBB");
                    flag = true;
                } else {
                    wait();
                }
                notify();
            }
        } catch (Exception e) {
        }
    }
}

 

可以结束

线程要以合理的方式放弃CPU控制权,一种方式是结束.当run()方法返回线程时,线程将撤销,其他线程可以接管CPU.在网络应用程序中,包装一个阻塞操作的线程往往会这么做,例如线程从服务器下载一个文件,这样应用程序的其他部分就不会被阻塞.另一方面,如果run()方法太简单,总是很快结束,而不会紫色,那就存在一个很实际的问题:到底有没有必要生成一个线程.虚拟机在建立和撤销线程时会有很大的开销.如果线程会在极端的时间内结束,那么使用一次简单的方法调用而不是单独的线程可能会结束的更快.

 

可以被更高优先级线程抢占

Thread的setPriority(int priority)设置线程的优先级.

 

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注三水点靠木的更多内容!

Java/Android 相关文章推荐
Spring Data JPA的Audit功能审计数据库的变更
Jun 26 Java/Android
Java中使用Filter过滤器的方法
Jun 28 Java/Android
java设计模式--原型模式详解
Jul 21 Java/Android
SpringBoot整合RabbitMQ的5种模式实战
Aug 02 Java/Android
深入浅出讲解Java8函数式编程
Jan 18 Java/Android
Java基础——Map集合
Apr 01 Java/Android
零基础学java之循环语句的使用
Apr 10 Java/Android
JAVA springCloud项目搭建流程
May 11 Java/Android
Java完整实现记事本代码
Jun 16 Java/Android
MyBatis XPathParser解析器使用范例详解
Jul 15 Java/Android
OpenFeign实现远程调用
Aug 14 Java/Android
Mybatis 一级缓存和二级缓存原理区别
Sep 23 Java/Android
Java 语言中Object 类和System 类详解
Jul 07 #Java/Android
新手初学Java List 接口
Jul 07 #Java/Android
Spring Boot 整合 Apache Dubbo的示例代码
Jul 04 #Java/Android
Java实现聊天机器人完善版
JavaGUI模仿QQ聊天功能完整版
JavaWeb Servlet实现网页登录功能
swagger如何返回map字段注释
You might like
SONY SRF-22W(33W)的电路分析和维修案例
2021/03/02 无线电
11个PHP 分页脚本推荐
2011/08/15 PHP
php漏洞之跨网站请求伪造与防止伪造方法
2013/08/15 PHP
php解析xml提示Invalid byte 1 of 1-byte UTF-8 sequence错误的处理方法
2013/11/14 PHP
PHP中set error handler函数用法小结
2015/11/11 PHP
PHP折半(二分)查找算法实例分析
2018/05/12 PHP
PHP利用百度ai实现文本和图片审核
2019/05/08 PHP
php设计模式之建造器模式分析【星际争霸游戏案例】
2020/01/23 PHP
JS 密码强度验证(兼容IE,火狐,谷歌)
2010/03/15 Javascript
JS 树形递归实例代码
2010/05/18 Javascript
dreamweaver 安装Jquery智能提示
2011/04/02 Javascript
jQuery中focus事件用法实例
2014/12/26 Javascript
JS检测页面中哪个HTML标签触发点击事件的方法
2016/06/17 Javascript
js拼接html字符串的注意事项
2016/10/13 Javascript
vue-axios使用详解
2017/05/10 Javascript
H5基于iScroll实现下拉刷新和上拉加载更多
2017/07/18 Javascript
vue中appear的用法
2017/08/17 Javascript
[54:05]DOTA2-DPC中国联赛定级赛 SAG vs iG BO3第一场 1月9日
2021/03/11 DOTA
python实现socket客户端和服务端简单示例
2014/02/24 Python
python实现简单的文字识别
2018/11/27 Python
Python 列表去重去除空字符的例子
2019/07/20 Python
Python for循环及基础用法详解
2019/11/08 Python
VSCode中自动为Python文件添加头部注释
2019/11/14 Python
tensorflow对图像进行拼接的例子
2020/02/05 Python
Python+redis通过限流保护高并发系统
2020/04/15 Python
python -v 报错问题的解决方法
2020/09/15 Python
PyQt5的QWebEngineView使用示例
2020/10/20 Python
用html5绘制折线图的实例代码
2016/03/25 HTML / CSS
工程现场管理求职自荐信
2013/10/02 职场文书
会计学应届毕业生推荐信
2013/11/04 职场文书
新闻工作者先进事迹
2014/05/26 职场文书
人与自然观后感
2015/06/16 职场文书
小学英语课教学反思
2016/02/15 职场文书
干货分享:推荐信写作技巧!
2019/06/21 职场文书
掌握这项技巧,一年阅读300本书不是梦
2019/09/12 职场文书
一篇文章学会Vue中间件管道
2021/06/20 Vue.js