package main

import (
	"fmt"
	"sync"
	"sync/atomic"
)

// RekapTanpaLock menyimpan total penjualan tanpa sinkronisasi apa pun.
// Dua goroutine yang memanggil Tambah bersamaan memicu data race.
type RekapTanpaLock struct {
	total int
}

// Tambah menambah nilai tanpa proteksi apa pun.
func (r *RekapTanpaLock) Tambah(n int) {
	r.total += n // baca-modifikasi-tulis tanpa sinkronisasi
}

// Total mengembalikan nilai total saat ini.
func (r *RekapTanpaLock) Total() int {
	return r.total
}

// RekapAmanMutex melindungi total dengan sync.Mutex.
type RekapAmanMutex struct {
	mu    sync.Mutex
	total int
}

// Tambah menambah nilai di dalam kunci mutex.
func (r *RekapAmanMutex) Tambah(n int) {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.total += n
}

// Total membaca nilai di dalam kunci mutex.
func (r *RekapAmanMutex) Total() int {
	r.mu.Lock()
	defer r.mu.Unlock()
	return r.total
}

// RekapAmanAtomic memakai atomic.Int64 untuk operasi tunggal.
type RekapAmanAtomic struct {
	total atomic.Int64
}

// Tambah menambah nilai secara atomik.
func (r *RekapAmanAtomic) Tambah(n int) {
	r.total.Add(int64(n))
}

// Total membaca nilai secara atomik.
func (r *RekapAmanAtomic) Total() int {
	return int(r.total.Load())
}

func main() {
	aman := &RekapAmanMutex{}
	atomik := &RekapAmanAtomic{}
	var wg sync.WaitGroup
	for range 2 {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for range 1000 {
				aman.Tambah(1)
				atomik.Tambah(1)
			}
		}()
	}
	wg.Wait()
	fmt.Println("Total dengan mutex :", aman.Total())
	fmt.Println("Total dengan atomic:", atomik.Total())
}
