java和go之间多线程之间的对比

Java线程和go协程之间的对比

在Java中多线程之间是通过共享内存进行通信的,在go中多线程之间通信是基于消息的,go中的通道是go中多线程通信的基石。

在java中创建的线程是与OS线程一一对应的,而在go中多个协程(goroutine)对应一个逻辑处理器,每个逻辑处理器与OS线程一一对应。

每个线程要运行必须要在就绪状态情况下获取cpu,而操作系统是基于时间片轮转算法来调度线程占用cpu来执行任务的,每个OS线程被分配一个时间片来占用cpu进行任务的执行。

在java中由于创建的线程与os线程一一对应,所以java中的每个线程占用一个时间片来运行。而go中多个协程对应一个os 线程,也就是多个协程对应了一个时间片,go则使用自己的调度策略(非os的调度策略)来让多个协程使用一个时间片来并发的运行。也就是go中存在两级策略,一个是go语言层面的调度多个协程公用一个时间片,一个是os层面的调度多个逻辑处理器轮询占用不同的时间片。

多任务之间信号量的通信

samephore(java) ------ waitgroup (go)
public final static Semaphore SEMAPHORE = new Semaphore(0);
    public static void main(String[] args) throws InterruptedException {

        Thread thread1 = new Thread(() -> {

            try {
                //run method dosomthing
                System.out.println(Thread.currentThread().getName() + "done");
            }finally {
                SEMAPHORE.release();
            }
            
        },"thread-1");
        thread1.start();
        
        
        Thread thread2 = new Thread(() -> {

            try {
                //run method dosomthing
                System.out.println(Thread.currentThread().getName() + "done");

            }finally {
                SEMAPHORE.release();
            }
            
        },"thread-2");
        thread2.start();
        
        System.out.println("wait all sub thread end");
        SEMAPHORE.acquire(2);
        System.out.println("all sub thread end");

    }


//创建同步器
var wg sync.WaitGroup

func main() {
    //两个信号
    wg.Add(2)

    //开启一个协程,执行匿名函数里面的内容
    go func() {
        //信号量减去1
        defer wg.Done()

        //do somthing
        fmt.Println("im A go 协程")

    }()

    //开启一个协程,执行匿名函数里面的内容
    go func() {
        //信号量减去1
        defer wg.Done()

        //do somthing
        fmt.Println("im B go 协程")

    }()

    fmt.Println("wait all sub thread end")
    wg.Wait()
    fmt.Println(" all sub thread end")

}

GO的内存模型 ???未知

  • Go语言的内存模型规定了一个goroutine可以看到另外一个goroutine修改同一个变量的值的条件,这类似java内存模型中内存可见性问题;

Happen Before 原则

channel的happen-before原则

  • 有缓冲的channel , 向channel中写入一个数据总是happen before 于这个这个数据从通道中读取完成
package main

import (
    "fmt"
)

var c = make(chan int, 10)
var a string

func f() {
    a = "hello, world" //1
    c <- 0             //2
}

func main() {
    go f()   //3
    <-c      //4
    fmt.Print(a) //5
}

  • 关闭通道的操作 happen before 从通道接受0值(关闭通道后会向通道发送一个0值)
package main

import (
    "fmt"
)

var c = make(chan int, 10)
var a string

func f() {
    a = "hello, world" //1
    close(c)            //2
}

func main() {
    go f()   //3
    <-c      //4
    fmt.Print(a) //5
}
  • 没有缓冲的channel,向通道中发送数据时必须确保通道中有接收的goroutine,所以通道中数据的接收Happen before 于数据的发送
package main

import (
    "fmt"
)

var c = make(chan int)
var a string

func f() {
    a = "hello, world" //1
    <-c                //2
}

func main() {
    go f()       //3
    c <- 0       //4
    fmt.Print(a) //5
}
  • 限制goroutine的并发数量–利用有缓存的channel
package main

import (
    "fmt"
    "time"
)

var limit = make(chan int, 3)
 
func sayHello(index int){
    fmt.Println(index )
}

var work []func(int)
func main() {
    
    work := append(work,sayHello,sayHello,sayHello,sayHello,sayHello,sayHello)
    
    for i, w := range work {
        go func(w func(int),index int) {
            limit <- 1
            w(index)
            <-limit
        }(w,i)
    }
    
    time.Sleep(time.Second * 10)
}
  • goroutine限制并发量, 每三个一个一组进行并发: 原理 == 每一组接收完成之后才能再次进行写入;==
  • 容量为C的通道接受第K个元素 happen before 向通道第k+C次写入完成,比如从容量为3的通道接受第2个元素 happen before 向通道第3+2次写入完成—也就是说 开始写 在 接收完成之后
package main

import (
	"fmt"
	"time"
)

var limit = make(chan int, 3)

func sayHello(index int){
	fmt.Println(index )
}

var work []func(int)
func main() {

	work := append(work,sayHello,sayHello,sayHello,sayHello,sayHello,sayHello)

	a :=0
	//todo 这样会每三个一组进行并发执行
	//算是一个替空间的过程-也就是说  开始写 在 接收完成之后
	for i, s := range work {
		go func(s func(int),index int) {
			limit <- 1
			if a < 3{
				time.Sleep(time.Second * 1)
				s(1)
			}else{
				s(2)
			}
			a++
			<-limit

		}(s,i)
	}

	time.Sleep(time.Second * 3)
	test_a()
}

func test_a (){
	a:=0
	for i:=0;i<10;i++{
		go func() {
			for j := 0; j < 1000; j++ {
				a++
			}
		}()
	}

	time.Sleep(3*time.Second)
	fmt.Println(a)
}
运行结果:
1
1
1
2
1
1
9441

once多个goroutine

  • 多个goroutine可以同时运行到once但只有一个能运行Do内的函数,然后所有的等待这个抢到这个执行权的goroutine执行完毕,然后在继续向下执行,once中的函数只执行一次;
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值